Serilog and IoC unity - frameworks

I'm trying to implement Serilog into my project but can't seem to get it working
I have this class where i call ILogger in the constructor but also tried to do a manual resolve in there.
private readonly ILogger logger;
private ILogger logger1;
public EstoxController(ILogger logger1)
{
this.logger = IoC.Container.Resolve<ILogger>();
this.logger1 = logger1;
}
And then i call it in a method that needs logging in the same class
public virtual ActionResult GetEstoxQueryUrl(string id, EstoxEnvironmentType environmentType)
{
var logger3 = IoC.Container.Resolve<ILogger>();
logger.Information("test");
logger1.Information("test");
logger3.Information("testing3");
And in my container configuration i have as followed.
Log.Logger = new LoggerConfiguration()
.WriteTo.File("logtesting.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
IoC.Container.RegisterInstance(Log.Logger);
I just can't seem to get it working please help

Looks like you need to specify the service when registering:
IoC.Container.RegisterInstance<ILogger>(Log.Logger);

Related

Autofac, accessing ContainerBuilder from random component

I am playing with Autofac and let's pretend i have a component (DLL) in my application that is using Logging. How and where to log will be defined by main App. So it registers ILog interface with Autofac.
Problem is how my component can get access to ContainerBuilder object to resolve ILog?
I can always initialize my component with IContainer but that defeats the purpose. I would just pass ILog interface to component instead of IContainer.
If I understand where you are with this correctly - it's worth reading up on the "Composition Root" for how to think about this in general. The short answer is "you don't access Containers from components."
https://blog.ploeh.dk/2011/07/28/CompositionRoot/
As you say, your component shouldn't know anything about Autofac - that actually goes for all of your code except a small section in your main application. So how does the ILog find its way to your component? From that Mark Seemann post:
"This means that all the application code relies solely on Constructor Injection"
That's a good general rule to make your code cleaner, even if you weren't using a DI framework. So in your situation, say you have a very simple app like this:
class Program
{
static void Main(string[] args)
{
var component = new Component(); // we want logging to happen inside here
component.DoStuff();
Console.ReadKey();
}
}
You actually just want to add your ILog as a dependency on your Component and then inject that as close as possible to your app-entry point:
public class Component
{
private readonly ILog _logger;
public Component(ILog logger)
{
_logger = logger;
}
public void DoStuff()
{
_logger.Log("this is a test");
}
}
class Program
{
static void Main(string[] args)
{
var container = GetContainer();
using (var scope = container.BeginLifetimeScope())
{
var test = scope.Resolve<Component>(); // this is potentially the only place we need to resolve anything
test.DoStuff();
}
Console.ReadKey();
}
private static IContainer GetContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<Component>();
builder.RegisterType<Logger>()
.As<ILog>();
var container = builder.Build();
return container;
}
}

guice JpaPersistModule with runtime configuration

I need to share datasource with JpaPersistModule. This datasource is provided by guice injector.
Now the problem I have to build module during configuration phase, but datasource is available only in runtime.
Currently I have following code:
public class MyJpaConfigurationModule implements Module {
private Map<String, Object> jpaProperties = new HashMap<>();
private Module jpaModule = new JpaPersistModule("peristenceUnit").properties(jpaProperties);
public void configure(Binder binder) {
binder.requestInjection(this);
binder.install(jpaModule);
}
#Provides #Singleton
public DataSource provideDatasource() {
return ..... // some data source
}
#Inject
public void setJpaProperties(DataSource dataSource, PersistService persistService) {
jpaProperties.put("dataSource", dataSource);
persistService.start();
}
}
I have checked and it seems that jpa properties map is everywhere injected by reference, so my runtime changes should become visible, but what if this changes in future?
What is the correct way to resolve such conflicts?

How to log queries using Entity Framework 7?

I am using Entity Framework 7 on the nightly build channel (right now I'm using version EntityFramework.7.0.0-beta2-11524) and I'm trying to log the queries that EF generates just out of curiosity.
I'm writing a simple console program, I tried using the same logging technic that EF6 uses, but DbContext.Database.Logis not available on Entity Framework 7. Is there a way to log or just take a peek at the SQL generated by EF7?
For those using EF7 none of the above worked for me. But this is how i got it working. (from #avi cherry's comment)
In your Startup.cs you proably have a Configure method with a bunch of configurations in it. It should look like below (in addition to your stuff).
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
//this is the magic line
loggerFactory.AddDebug(LogLevel.Debug); // formerly LogLevel.Verbose
//your other stuff
}
You can log to the console using this code, I am sure it will be wrapped in a simpler api later:
using System;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Data.Entity.Utilities;
using Microsoft.Framework.Logging;
public static class SqlCeDbContextExtensions
{
public static void LogToConsole(this DbContext context)
{
var loggerFactory = ((IAccessor<IServiceProvider>)context).GetService<ILoggerFactory>();
loggerFactory.AddProvider(new DbLoggerProvider());
}
}
And the DbLoggerProvider is implemented here: https://github.com/ErikEJ/EntityFramework7.SqlServerCompact/tree/master/src/Provider40/Extensions/Logging
If you are using MS SQL Server, one way I have used in the past is to make use of the SQL Server Profiler and capture all interaction with the SQL Server, this captures the exact SQL submitted and can be cut n pasted into the SQL Server Management Studio for further review/analysis.
I know this does not directly answer your question on Entity Framework, but I have found this generic approach very useful for any language/tools.
One tip is in the Trace Properties when setting up a new trace, I have found it useful to adjust the default selection of events in the Events Selection tab. Mostly I turn off the Audit Login/Logout unless specifically tracking such an issue.
I struggled with all the above answers as the EF bits kept changing, so the code wouldn't compile. As of today (19Feb2016) with EF7.0.0-rc1-final (Prerelease) and SQLite, here's what works for me:
From the EF7 documentation:
using System;
using System.IO;
using Microsoft.Extensions.Logging;
namespace EFLogging
{
public class EFLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName)
{
return new EFLogger();
}
public void Dispose()
{
// N/A
}
private class EFLogger : ILogger
{
public IDisposable BeginScopeImpl(object state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
File.AppendAllText(#".\EF.LOG", formatter(state, exception));
Console.WriteLine(formatter(state, exception));
}
}
}
}
Using some ideas above and the EF7 Docs:
using System;
using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Infrastructure;
using Microsoft.Extensions.DependencyInjection; // Add this to EF7 docs code
using Microsoft.Extensions.Logging;
namespace DataAccessLayer
{
public static class DbContextExtensions
{
public static void LogToConsole(this DbContext context)
{
var serviceProvider = context.GetInfrastructure<IServiceProvider>();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
loggerFactory.AddProvider(new EFLoggerProvider(logLevel));
}
}
}
EDIT: #jnm2 pointed out if you add "using Microsoft.Extensions.DependencyInjection", the EF7 docs ARE correct. Thanks!
And finally, in my App.OnStartup method:
using (var db = new MyDbContext())
{
db.LogToConsole();
}
This code will create a log file and also output logging info to the Visual Studio output window. I hope this helps -- I'm sure in a few weeks, the bits will change again.
With the latest version of EF7-beta8, Anthony's answer need a little tweaking. Here's what I did to get it to work.
internal static class DbContextExtensions
{
public static void LogToConsole(this DbContext context)
{
var loggerFactory = context.GetService<ILoggerFactory>();
loggerFactory.AddConsole(LogLevel.Verbose);
}
}
I think I figured this out. With the current EF7 bits, ILoggerFactory is registered with the dependency injection container which EF is using. You can get a reference to the container, which is an IServiceProvider, via the ScopedServiceProvider property of DbContext when it is cast to IDbContextServices. From there, you can get the ILoggerFactory and configure it using the AddToConsole extension method from the Microsoft.Framework.Logging.Console NuGet package.
public static void LogToConsole(this DbContext context)
{
// IServiceProvider represents registered DI container
IServiceProvider contextServices = ((IDbContextServices)context).ScopedServiceProvider;
// Get the registered ILoggerFactory from the DI container
var loggerFactory = contextServices.GetRequiredService<ILoggerFactory>();
// Add a logging provider with a console trace listener
loggerFactory.AddConsole(LogLevel.Verbose);
}
Here is a gist I created for this snippet: https://gist.github.com/tonysneed/4cac4f4dae2b22e45ec4
This worked for me with EF7 rc2-16485:
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc2-16485",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc2-15888",
public static class DbContextExtensions
{
public static void LogToConsole(this DbContext context)
{
var contextServices = ((IInfrastructure<IServiceProvider>) context).Instance;
var loggerFactory = contextServices.GetRequiredService<ILoggerFactory>();
loggerFactory.AddConsole(LogLevel.Verbose);
}
}
As an alternative to the above answers, I found this answer by far the easiest solution for me to reason about:
private readonly ILoggerFactory loggerFactory;
// Using dependency injection
public FooContext(ILoggerFactory loggerFactor) {
this.loggerFactory = loggerFactory;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseLoggerFactory(loggerFactory); // Register logger in context
}
With ASP.NET Core 2.0 you get SQL logging automatically. No need to do anything extra.
For those who just want SQL queries to be logged (using Entity Framework Core with .NET Core 2.0 or above), use the following code in your DbContext class:
public static readonly LoggerFactory MyLoggerFactory
= new LoggerFactory(new[]
{
new ConsoleLoggerProvider((category, level)
=> category == DbLoggerCategory.Database.Command.Name
&& level == LogLevel.Information, true)
});
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLoggerFactory(MyLoggerFactory) // Warning: Do not create a new ILoggerFactory instance each time
.UseSqlServer(
#"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True;ConnectRetryCount=0");
Reference: https://learn.microsoft.com/en-us/ef/core/miscellaneous/logging

"No parameterless constructor" error instantiating Controller registered w/Windsor Container

Using MVC and trying to use dependency injection for controllers, but when I try to call a method on a controller that takes a dependency, I get the "no parameterless constructor" error. Here's my setup:
ProductRepository : IProductRepository
ProductService : IProductService {
public ProductService(IProductRepository repository) {} }
ProductController {
public ProductController(IProductService service) {} }
In Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
InitializeServiceLocator();
RegisterRoutes(RouteTable.Routes);
}
protected virtual void InitializeServiceLocator()
{
IWindsorContainer container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));
container.RegisterControllers(typeof(HomeController).Assembly);
ComponentRegistrar.AddComponentsTo(container);
foreach (var handler in container.Kernel.GetAssignableHandlers(typeof(object)))
{
System.Diagnostics.Debug.WriteLine(String.Format("{0} {1}",
handler.ComponentModel.Service,
handler.ComponentModel.Implementation));
}
ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container));
}
ComponentRegistrar:
public static void AddComponentsTo(IWindsorContainer container)
{
AddCustomRepositoriesTo(container);
AddApplicationServicesTo(container);
}
When InitializeServiceLocator completes, I can see that all Controllers, Services and Repositories are registered.
Any help greatly appreciated.
I'd still like to know the problem, but I've worked around it by creating my own WindsorControllerFactory per this post (with modification to avoid any web.config action): http://mvcsharp.wordpress.com/2010/01/09/setting-up-ioc-in-asp-net-mvc-using-castle-windsor/
The WindsorControllerFactory in the previous code was the MvcContrib.Castle.WindsorControllerFactory. Anyone using MvcContrib version successfully?
Thanks.

Resolve externally created object instance with no public constructor

Using the adapter pattern, combined with IoC (specificly Unity), I would like to create a new instance of a object of which the properties point back to the adaptee's propeties (basicly mapping the adaptee to a target object).
As a example I have the following class structures:
public class Adaptee
{
private Adaptee() { }
public int MyProperty { get; set; }
public static Adaptee New()
{
return new Adaptee();
}
}
public class Target
{
public int MyProperty { get; set; }
}
public class Adapter : Target
{
public Adapter(Adaptee adaptee)
{
this.MyProperty = adaptee.MyProperty;
}
}
public class MyTestClass
{
public Target MyTarget { get; set; }
}
The problem is that the Adaptee is not under my control and it has no public constructor, hence the use of the adapter. So Adaptee gets created as follow
Adaptee adaptee = Adaptee.New();
adaptee.MyProperty = 5;
In the actual code the above code would be executed in a externally controlled assembly and then passed to the following code:
using (UnityContainer container = new UnityContainer())
{
container
.RegisterType<MyTestClass>(
new InjectionProperty("MyTarget"));
container.RegisterInstance<Adaptee>(adaptee, new ExternallyControlledLifetimeManager());
MyTestClass myTestClass = container.Resolve<MyTestClass>();
}
I would like the execution of the code to result in the following:
Debug.Assert(myTestClass != null);
Debug.Assert(myTestClass.MyTarget != null);
Debug.Assert(myTestClass.MyTarget.MyProperty == adaptee.MyProperty);
This means that a resolved instance of Adapter should be injected into the MyTarget property of the myTestClass instance. The instance of Adapter should have been created with externally created instance of Adaptee.
The following code:
container
.RegisterType<MyTestClass>(
new InjectionProperty("MyTarget"));
should actually result in this:
container
.RegisterType<MyTestClass>(
new InjectionProperty("MyTarget", container.Resolve<Adapter>()));
This does not seem to be possible, since no instance of Adapter exist yet and it has a private constructor.
Should I use interception or something to achive this?
I was close with the container.Resolve<Adapter>() idea, but the final answer is simply to use the ResolvedParameter class when configuring the property to be injected using the InjectionProperty class:
new InjectionProperty(
"MyTarget",
new ResolvedParameter<Adapter>()));
So the calling code would look as follow:
Adaptee adaptee = Adaptee.New();
adaptee.MyProperty = 5;
using (UnityContainer container = new UnityContainer())
{
container
.RegisterType<MyTestClass>(
new InjectionProperty(
"MyTarget",
new ResolvedParameter<Adapter>()));
container.RegisterInstance<Adaptee>(adaptee, new ExternallyControlledLifetimeManager());
MyTestClass myTestClass = container.Resolve<MyTestClass>();
}
I found the solution in the following post:
Setter / property injection in Unity without attributes
Hope this helps someboby else.
That was a Doh! moment.
The solution is to add the following when configuring unity:
.RegisterType<Target, Adapter>()
I can't believe I missed that, such a simple solution which solves the problem (I think).
So te MyTarget property on the MyTestClass will resolve to a instance of the Adapter since it inherits from Target. The Adapter will obviously be initiated with the externally created instance of the Adaptee class.