I've encountered a problem while upgrading from AutoMapper's static API.
I'm following the example on this page, which states that
Typical usage from 4.1 and before was:
Mapper.Initialize(cfg => {
cfg.AddProfile<AppProfile>();
cfg.CreateMap<Source, Dest>(); });
var dest = Mapper.Map<Source, Dest>(new Source());
In 4.2 and later, this would look like:
var config = new MapperConfiguration(cfg => {
cfg.AddProfile<AppProfile>();
cfg.CreateMap<Source, Dest>();
});
var mapper = config.CreateMapper();
var dest = mapper.Map<Source, Dest>(new Source());
However, while using v4.2.1 via NuGet I can't see this 'CreateMapper' method.
What am I supposed to use?
I've realised what was causing my problem.
In order to use the MapperConfiguration application-wide I was storing it as a static property:
public static IMapperConfiguration { get; private set; }
public static void Init()
{
MapperConfiguration = new MapperConfiguration(...);
...
MapperConfiguration. // CreateMapper() not available
}
The problem here is that the CreateMapper method is only available on the MapperConfiguration class, not the IMapperConfiguration interface.
Related
I'm using the slf4net.log4net nuget package to handle logging in a project. Because it must be possible for the loglevel to change at runtime, I made the configuration in code. The issue is that this code works fine in slf4net.log4net version 0.1.32.1 but when I upgrade it to version 1.0.0, the logfile is created, but the logs are not present on the logfile. I've created a dummy project to show this issue. I do not see how I can add a zip file here, so I'll just post the code here. It is a console app in net framework 4.7.2;
class Program
{
private static string GetLoggingPath()
{
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData,
Environment.SpecialFolderOption.DoNotVerify), "LoggingTesting");
Directory.CreateDirectory(path);
return path;
}
static void Main(string[] args)
{
var layout = new PatternLayout
{
ConversionPattern = "%d{ABSOLUTE}: %message %newline"
};
layout.ActivateOptions();
var fileAppender = new RollingFileAppender();
fileAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date;
fileAppender.Layout = layout;
var path = GetLoggingPath();
fileAppender.File = path + System.IO.Path.DirectorySeparatorChar + "LISlogging_.txt";
fileAppender.AppendToFile = true;
fileAppender.PreserveLogFileNameExtension = true;
fileAppender.StaticLogFileName = false;
fileAppender.DatePattern = "yyyy-MM-dd";
fileAppender.MaxSizeRollBackups = 10;
fileAppender.ActivateOptions();
ILoggerRepository repository = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
BasicConfigurator.Configure(repository, fileAppender);
var root = (repository as Hierarchy)?.Root;
if (root == null) return;
root.Level = log4net.Core.Level.All;
// Create log4net ILoggerFactory and set the resolver
var factory = new slf4net.log4net.Log4netLoggerFactory();
var resolver = new SimpleFactoryResolver(factory);
slf4net.LoggerFactory.SetFactoryResolver(resolver);
// trigger logging
var log = slf4net.LoggerFactory.GetLogger(typeof(Program));
log.Info("log this line");
}
}
public class SimpleFactoryResolver : IFactoryResolver
{
private readonly slf4net.ILoggerFactory _factory;
public SimpleFactoryResolver(slf4net.ILoggerFactory factory)
{
_factory = factory;
}
public slf4net.ILoggerFactory GetFactory()
{
return _factory;
}
}
This dummy project was created in .net framework, but I need this in a .net core project. That is why I need to version 1.0.0 .
I've also post this issue on the github page of slf4net (because it looks like a bug) : https://github.com/ef-labs/slf4net/issues/6
My main question for here on stack overflow is if there is a workaround so this can work with slf4net.log4net version 1.0.0
I've found a workaround for this. Maybe not the cleanest solution but it works. If anyone knows a cleaner solution please add it here.
When looking at the slf4net.log4net code I found out that when it tries to configure log4net it uses xml files or config files, which is a nightmare if you want to set the loglevel at runtime. You can pass a customconfigurator as parameter of the Log4netLoggerFactory . This customconfigurator needs to implement IXmlConfigurator.
The CustomConfigurator I've made accepts an IAppender and a loglevel (log4net.Core.Level). In the implementation of the Configure(ICollection(ILoggerRepository repository) method. I've set the root log level and Configured with the BasicConfigurator.
The CustomConfigurator looks like this:
public class CustomConfigurator: IXmlConfigurator
{
private readonly IAppender _appender;
private readonly log4net.Core.Level _logLevel;
public CustomConfigurator(IAppender appender, log4net.Core.Level logLevel)
{
_appender = appender;
_logLevel = logLevel;
}
public ICollection Configure(ILoggerRepository repository)
{
var root = (repository as Hierarchy)?.Root;
if (root != null)
{
root.Level = _logLevel;
}
return BasicConfigurator.Configure(repository, _appender);
}
public ICollection Configure(ILoggerRepository repository, XmlElement element)
{
return XmlConfigurator.Configure(repository, element);
}
public ICollection Configure(ILoggerRepository repository, FileInfo configFile)
{
return XmlConfigurator.Configure(repository, configFile);
}
public ICollection ConfigureAndWatch(ILoggerRepository repository, FileInfo configFile)
{
return XmlConfigurator.ConfigureAndWatch(repository, configFile);
}
}
Now you can create an appender in code like shown in the question (until fileappender.ActivateOptions) Then when constructing the log4netLoggerFactory you pass an instance of CustomConfigurator which takes the fileAppender and a loglevel as parameter.
var factory = new slf4net.log4net.Log4netLoggerFactory(new CustomConfigurator(fileAppender, Level.All));
var resolver = new SimpleFactoryResolver(factory);
slf4net.LoggerFactory.SetFactoryResolver(resolver);
This should work.
Does anyone know how to configure AutoMapper using LightInject? The AutoMapper documentation only has examples for Ninject and Simple Injector.
I am having difficulty trying to register the AutoMapper configuration.
I'm using ASP.NET MVC C#.
public class CompositionRoot : ICompositionRoot
{
public void Compose(IServiceRegistry serviceRegistry)
{
serviceRegistry.Register(c => new AutoMapperConfiguration());
}
}
public static class AutoMapperConfiguration
{
public AutoMapperConfiguration()
{
Mapper.Initialize(cfg =>
cfg.AddProfiles(typeof(Namespace.Class).Assembly)
);
}
}
I figured it out. The code below is in the CompositionRoot, where the factory is registered using IServiceRegistry. I will be moving the var config = new MapperConfiguration(cfg => cfg.AddProfiles(typeof(CustomProfileClass).Assembly)); code to a custom MapperConfiguration class that I will create.
public class CompositionRoot : ICompositionRoot
{
public void Compose(IServiceRegistry serviceRegistry)
{
var config = new MapperConfiguration(cfg => cfg.AddProfiles(typeof(CustomProfileClass)));
serviceRegistry.Register(c => config.CreateMapper());
}
}
I'm getting an error when i try to run some tests on my servicestack web service.
I'm using ServiceStack 4.5.8 and Nunit 3.5. The solution was created initially from a ServiceStackVS template.
The error, which appears on a number of tests, is
System.IO.InvalidDataException : ServiceStackHost.Instance has already been set (BasicAppHost)</br>
TearDown : System.NullReferenceException : Object reference not set to an instance of an object.</br>
at ServiceStack.ServiceStackHost.Init()</br>
at MyApp.Tests.EchoServiceUnitTests.OneTimeSetup() in </br>
C:\Repos\MyApp\Myapp\MyApp.Tests\EchoServiceUnitTests.cs:line 45 </br>
--TearDown</br>
at MyApp.Tests.EchoServiceUnitTests.TestFixtureTearDown() in </br>C:\Repos\MyApp\MyApp\MyApp.Tests\EchoServiceUnitTests.cs:line 54
One of the tests that regularly generates this error is
namespace Tests
{
[TestFixture]
public class EchoServiceUnitTests
{
private ServiceStackHost appHost;
[OneTimeSetUp]
public void OneTimeSetup()
{
this.appHost = new BasicAppHost(typeof(EchoService).Assembly).Init();
}
[OneTimeTearDown]
public void TestFixtureTearDown()
{
this.appHost.Dispose();
}
[Test]
public void TestService()
{
const string Message = "Hello";
var service = this.appHost.Container.Resolve <EchoService>();
var response = (EchoResponse)service.Any(new Echo
{
Message = Message
});
Assert.That(response.Message,
Is.EqualTo(Message));
}
}
}
the service for this is
namespace ServiceInterface
{
public class EchoService : Service
{
public object Any(Echo request)
{
return new EchoResponse {Message = request.Message};
}
}
}
[Route("/Echo")]
[Route("/Echo/{Message}")]
public class Echo : IReturn<EchoResponse>
{
public string Message { get; set; }
}
public class EchoResponse : IHasResponseStatus
{
public EchoResponse()
{
this.ResponseStatus = new ResponseStatus();
}
public string Message { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
And finally my apphost
namespace MyApplication
{
using System;
using Funq;
using ServiceInterface;
using ServiceModel.Validators;
using ServiceStack;
using ServiceStack.Admin;
using ServiceStack.Api.Swagger;
using ServiceStack.Caching;
using ServiceStack.Configuration;
using ServiceStack.Logging;
using ServiceStack.Logging.NLogger;
using ServiceStack.MsgPack;
using ServiceStack.OrmLite;
using ServiceStack.OrmLite.SqlServer.Converters;
using ServiceStack.ProtoBuf;
using ServiceStack.Razor;
using ServiceStack.Validation;
using ServiceStack.VirtualPath;
using ServiceStack.Wire;
public class AppHost : AppHostBase
{
public static ILog Log = LogManager.GetLogger(typeof(AppHost));
public AppHost()
: base("MyApp",
typeof(HelloService).Assembly) { }
public override void Configure(Container container)
{
LogManager.LogFactory = new NLogFactory();
Log = LogManager.GetLogger(this.GetType());
this.Plugins.Add(new RazorFormat());
this.Plugins.Add(new PostmanFeature());
this.Plugins.Add(new SwaggerFeature());
this.Plugins.Add(new AdminFeature());
var ormSettings = new AppSettings();
container.Register <ICacheClient>(new MemoryCacheClient());
var dbFactory = new OrmLiteConnectionFactory(ormSettings.GetString("SqlDbConnection"),
SqlServerDialect.Provider);
dbFactory.RegisterConnection("Database2",
ormSettings.GetString("Sql2Connection"),
SqlServerDialect.Provider);
SqlServerDialect.Provider.RegisterConverter<DateTime?>(new SqlServerDateTimeConverter());
this.Plugins.Add(new RequestLogsFeature
{
RequestLogger = new CsvRequestLogger(files: new FileSystemVirtualPathProvider(this,
this.Config.WebHostPhysicalPath),
requestLogsPattern: "requestlogs/{year}-{month}/{year}-{month}-{day}.csv",
errorLogsPattern: "requestlogs/{year}-{month}/{year}-{month}-{day}-errors.csv",
appendEvery: TimeSpan.FromSeconds(1)),
EnableRequestBodyTracking = true,
EnableResponseTracking = true,
EnableErrorTracking = true,
});
this.Plugins.Add(new AutoQueryDataFeature
{
MaxLimit = 1000
});
this.Plugins.Add(new AutoQueryFeature());
var sse = new ServerEventsFeature
{
StreamPath = "/event-stream",
HeartbeatPath = "/event-heartbeat",
UnRegisterPath = "/event-unregister",
SubscribersPath = "/event-subscribers",
LimitToAuthenticatedUsers = false,
IdleTimeout = TimeSpan.FromSeconds(30),
HeartbeatInterval = TimeSpan.FromSeconds(10),
NotifyChannelOfSubscriptions = true,
};
this.Plugins.Add(sse);
Plugins.Add(new AdminFeature());
Plugins.Add(new WireFormat());
Plugins.Add(new MsgPackFormat());
Plugins.Add(new ProtoBufFormat());
}
}
}
I've tried a variety of suggestions including making the apphost in the test static, but nothing seems to work for me. I then tried the following test which also generated the same error which suggests to me that there is something in the apphost which is wrong but I can't see what.
[TestFixture(Category = "AppHost")]
public class AppHostTests
{
/// <summary>
/// The app host doesnt throw exception.
/// </summary>
[Test]
public void AppHostDoesntThrowException()
{
var apphost = new AppHost();
Assert.That(() => apphost.Init(),
Throws.Nothing);
}
}
The tests that generate this error whether I am using NCRUNCH (set to run one at a time) or if I use resharpers run all tests. It's generally the same tests that generate this error, though that seems to vary. In all cases, if I then run the tests manually they all pass.
You can only have 1 AppHost initialized and running at the same time where somehow NCrunch test is being run whilst there is another AppHost still in use. Maybe you can try debugging and setting a breakpoint that checks if ServiceStackHost.Instance is not null before trying to initialize another AppHost.
Note the AppHostBase is an ASP.NET Web App which may be causing the interference if it's running in the same project as the unit tests. If you want an integration test use AppSelfHostBase instead which you would use in place of BasicAppHost where you'd want to run a full integration test.
I'm using Ninject in a new Azure WebJobs project. One of my repositories requires a Db client to be passed. How do I pass this client?
My bindings class is:
public class NinjectBindings : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<IMyRepository>().To<MyRepository>();
}
}
My Main function in the console app looks like this:
static void Main()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
var config = new Configuration();
config.AddJsonFile("appsettings.json");
DbClient _dbClient = new DbClient(config);
IMyRepository myRepository = kernel.Get<IMyRepository>(); // This is where I get an error
}
My repository code is like this which is expecting the DbClient
public class MyRepository : IMyRepository
{
private DbClient _client;
public MyRepository(DbClient client)
{
_client = client;
}
}
You need to setup a binding for your DbClient.
I'd suggest being cautious around when components are released. I've not seen a good ninject example for web jobs yet so I've wired up manually. But that's just my thoughts...
I'm trying to write a target for NLog to send messages out to connected clients using SignalR.
Here's what I have now. What I'm wondering is should I be using resolving the ConnectionManager like this -or- somehow obtain a reference to the hub (SignalrTargetHub) and call a SendMessage method on it?
Are there performance ramifications for either?
[Target("Signalr")]
public class SignalrTarget:TargetWithLayout
{
public SignalR.IConnectionManager ConnectionManager { get; set; }
public SignalrTarget()
{
ConnectionManager = AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
}
protected override void Write(NLog.LogEventInfo logEvent)
{
dynamic clients = GetClients();
var logEventObject = new
{
Message = this.Layout.Render(logEvent),
Level = logEvent.Level.Name,
TimeStamp = logEvent.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss.fff")
};
clients.onLoggedEvent(logEventObject);
}
private dynamic GetClients()
{
return ConnectionManager.GetClients<SignalrTargetHub>();
}
}
I ended up with the basic the same basic structure that I started with. Just a few tweaks to get the information I needed.
Added exception details.
Html encoded the final message.
[Target("Signalr")]
public class SignalrTarget:TargetWithLayout
{
protected override void Write(NLog.LogEventInfo logEvent)
{
var sb = new System.Text.StringBuilder();
sb.Append(this.Layout.Render(logEvent));
if (logEvent.Exception != null)
sb.AppendLine().Append(logEvent.Exception.ToString());
var message = HttpUtility.HtmlEncode(sb.ToString());
var logEventObject = new
{
Message = message,
Logger = logEvent.LoggerName,
Level = logEvent.Level.Name,
TimeStamp = logEvent.TimeStamp.ToString("HH:mm:ss.fff")
};
GetClients().onLoggedEvent(logEventObject);
}
private dynamic GetClients()
{
return AspNetHost.DependencyResolver.Resolve<IConnectionManager>().GetClients<SignalrTargetHub>();
}
}
In my simple testing it's working well. Still remains to be seen if this adds any significant load when under stress.