I can inject the ILogger into a controller but I'm having an issue trying to inject it into a repository class.
Here is my Startup method:
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Error()
.WriteTo.RollingFile(Path.Combine(
env.WebRootPath, "log-{Date}.txt"))
.CreateLogger();}
This is in my Configure method:
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddSerilog();
My Controller:
private readonly ISkillsRepo _repo;
private readonly ILogger _logger;
public HistoryAndReportsController(Context db, ILogger<SkillsRepo> logger)
{
_repo = new SkillsRepo(db, logger);
_logger = logger;
}
The repo:
private readonly Context _db;
private readonly ILogger _logger;
public SkillsRepo(Context db, ILogger<SkillsRepo> logger)
{
_db = db;
_logger = logger;
}
I can inject the logger into the controller and then pass it to the repo but there must be a way to inject the logger into the repo directly but I can't find any examples.
I can create another logger instance in the repo but that defeats the purpose of DI. I have the same issue understanding how to do the same with the DBContext.
As it has already been mentioned you need to register your repository in the dependency injection (DI) container first.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IUserRepository, AwesomeUserRepository>();
...
}
ILoggerFactory (and therefore ILogger<T>) are framework provided injections and don't need to be added manually.
Igor's answer was the solution with the addition of adding your repo to the services otherwise you get an error.
"Unable to resolve service for type "
Related
Following a tutorial on how to use Serilog I read the settings from an appsettings.json file - and all below works well, when things are simple:
Main program (in simple MVP version):
public static void Main(string[] args)
{
//Read Configuration from appSettings
var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
//Initialize Logger
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(config).CreateLogger();
try
{
Log.Information("Starting up the service");
CreateHostBuilder(args).Build().Run();
....
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
})
.UseSerilog();
Then the class with the BackgroundService:
....
using Microsoft.Extensions.Logging;//and not Serilog!!
public class Worker : BackgroundService
{
private readonly ILogger _logger;
....
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
---------------------SIMPLE THINGS FOR ME ENDS HERE :-) ----------------------------------
Now, I want to build it up to a "real" program from this first MVP - placing function in seperate classes according to SOLID principles.For instance my first class is a ConfigurationCollector collecting all relevant paramters from the appsettings.json file that I place in a seperat class. The class works and does it jobs - but I want logging to work - and I try to use the allready configured Serilog logger used accross class (just as I did with ILogger, so that the Worker object creates a new ConfigurationCollector class like
public Worker(ILogger<Worker> logger)
{
_logger = logger;
_configCollector = new ConfigCollector(logger);
}
I know that logger is now a type of
ILogger<ConfigCollector>
which is not
ILogger<Worker>
But how do I inject the original Serilog from the initiation of the service into each class used, such that the objects are shown properly in the logs?
public class ConfigCollector
{
private readonly ILogger<ConfigCollector> _logger;
....
public ConfigCollector(ILogger<ConfigCollector> logger)
{
_logger = logger;
}
.NET 6 Background service
.UseSerilog((builder, loggerConfig) =>
loggerConfig.ReadFrom.Configuration(builder.Configuration))
.Build();
With ASP.NET MVC Core it is possible to use the Unity DI packages by loading the appropriate NuGet packages (Unity.Container and Unity.Microsoft.DependencyInjection) and then calling the UseUnityServiceProvider() extension method when building the web host in Program.cs. This extension method is based off of the IWebHostBuilder interface. After initializing the host it is possible to access the Unity DI functionality via the .NET Core GetService interface and any constructor injection.
I'm working on a console based application that will use HostBuilder and the IHostBuilder interface. I've tried reimplementing the registration logic from the UseUnityServiceProvider() extension (available here: https://github.com/unitycontainer/microsoft-dependency-injection/blob/master/src/HostingExtension.cs) as part of the ConfigureServices() method call against IHostBuilder, but the change in service provider does not appear to be visible to downstream DI calls.
Has anyone been successful in getting Unity to work with the Microsoft DI methods in an application created using HostBuilder?
Update As requested, here is an example of what I was trying (taken from the Unity source). Of course, this does not work. TestService has a constructor which should be injected with an object defined in MyUnityExtension. This does not happen.
private static async Task MainTest()
{
var container = new UnityContainer().AddNewExtension<MyUnityExtension>();
var factory = new ServiceProviderFactory(container);
var hostBuilder = new HostBuilder()
.ConfigureServices((hostBuilderContext, services) =>
{
services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IUnityContainer>>(factory));
services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(factory));
services.AddHostedService<TestService>();
});
await hostBuilder.RunConsoleAsync();
}
Not sure what you want to achieve with new UnityContainer().AddNewExtension<MyUnityExtension>().
If you just want some registered service to be injected into TestService, why not just use IUnityContainer.RegisterType<TInterface, TImplementation>() ?
Here is a working IHost setup in Program.cs (.NET Core 3.1, Microsoft.Extensions.Hosting v3.10, Unity.Microsoft.DependencyInjection v5.11.5):
public static async Task Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IService, MyService>();
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<TestService>();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole();
})
.UseUnityServiceProvider(container);
await builder.RunConsoleAsync();
}
The interface:
public interface IService
{
string Name { get; }
}
The implementation:
public class MyService : IService
{
public string Name => "My name";
}
The TestService:
public class TestService : IHostedService
{
private readonly IService service;
private readonly ILogger logger;
public TestService(IService service, ILogger<TestService> logger)
{
this.service = service;
this.logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
this.logger.LogInformation("Hello {n}", this.service.Name);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
I'm working in an Azure webJob.
I'm using autofac with a IJobActivator an everything is ok.
But now, I need to call code that is using IServiceProvider and at that moment I get an error from Autofac because IServiceProvider is not known.
When I'm using the Microsoft.Extensions.DependencyInjection.ServiceCollection() to register my Interfaces in place of Autofac it is working (I don't know where the IServiceProvider is registered but it is working).
The company I work for is asking me to explicitly use Autofac.
I struggle to find to way to use Autofac but declare the IServiceProvider within the WebJob.
Have someone an idea?
I need to call code that is using IServiceProvider and at that moment I get an error from Autofac because IServiceProvider is not known.
Does that mean when running your Webjob, you could not find the IServiceProvider in AutofacActivator.
I am not clear about how do you define IServiceProvider and how do you inject it?
I think you could inject IServiceProvider into job activator and register it then you could use this instance to get service.
You could register the IServiceProvider interface before build in ContainerConfig:
public static class ContainerConfig
{
public static IContainer GetContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<Functions>();
builder.RegisterType<HelloGenerator>().As<IStringGenerator>().SingleInstance();
builder.Register<IServiceProvider>(context =>
{
var serviceCollection = new ServiceCollection();
//todo: register the interfaces
return serviceCollection.BuildServiceProvider();
}).SingleInstance();
return builder.Build();
}
}
Get service when triggered in Functions:
public class Functions
{
private readonly IStringGenerator _stringGenerator;
private readonly IServiceProvider _serviceProvider;
public Functions(IStringGenerator strGenerator,IServiceProvider serviceProvider)
{
_stringGenerator = strGenerator;
_serviceProvider = serviceProvider;
}
public void ProcessQueueMessage([QueueTrigger("queue")] string message, TextWriter log)
{
log.WriteLine(_stringGenerator.GetWord());
log.WriteLine(_serviceProvider.GetService(xxxxxx));
}
}
In Progtam:
static void Main()
{
var config = new JobHostConfiguration
{
JobActivator = new AutofacActivator(ContainerConfig.GetContainer())
};
var host = new JobHost(config);
host.RunAndBlock();
}
In AutofacActivator:
public class AutofacActivator : IJobActivator
{
private readonly IContainer _container;
public AutofacActivator(IContainer container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Resolve<T>();
}
}
If this is not what you want, hope you could give me more detailed description and your main idea code.
In fact I solved my issue by using Extensions:
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
by using them doing the following:
_containerBuilder = new ContainerBuilder();
_containerBuilder.Populate(new ServiceCollection());
_containerBuilder.RegisterType<MyGreatType>().InstancePerDependency();
_container = _containerBuilder.Build();
It generates automatically the IServiceProvider for you
I have installed the Hangfire.Ninject package to an ASP MVC 5 application so that I can run some background jobs.
I've read through the documentation but I'm baffled as to how to implement it.
My existing configuration uses InRequestScope for my IUnitOfwork class to ensure only a single instance is instantiated per HTTP request as follows:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
}
To use ninject with hangfire having followed the documentation I have updated the configuration as follows in my ninjectwebcommon.cs class:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
GlobalConfiguration.Configuration.UseNinjectActivator(kernel);
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>()
.ToSelf()
.InNamedOrBackgroundJobScope(context => context.Kernel.Components.GetAll<INinjectHttpApplicationPlugin>()
.Select(c => c.GetRequestScope(context))
.FirstOrDefault(s => s != null));
}
But now I get the following error:
Error activating IUnitOfWork using self-binding of IUnitOfWork
No constructor was available to create an instance of the implementation type.
I have a class I would like to use to process my background job using hangfire is as follows:
public class EmailJob
{
private readonly IUnitOfWork _unitOfWork;
private readonly IMailer _mailer;
public EmailJob(IUnitOfWork unitOfWork, IMailer mailer)
{
_unitOfWork = unitOfWork;
_notificationMailer = notificationMailer;
}
public void Execute()
{
// DO Stuff
}
}
Any one know what I'm doing wrong? The documentation also states:
Services registered with InRequestScope() directive will be unavailable during job activation, you should re-register these services without this hint.
What does this mean? I still want to ensure that only one IUnitOfwork class which implement dbContext is used per http request. How is this now going to affect the rest of the application if I remove the InRequestScope?
I think the issue is that you are binding IUnitOfWork to itself.
Niject would need a concrete class to activate something like UnitOfWork.
kernel.Bind<IUnitOfWork>()
.To<UnitOfWork()
.InNamedOrBackgroundJobScope(context => context.Kernel.Components.GetAll<INinjectHttpApplicationPlugin>()
.Select(c => c.GetRequestScope(context))
.FirstOrDefault(s => s != null));
Prepare for a wall of code... It's a long read, but it's as verbose as I can get.
In response to Still lost on Repositories and Decoupling, ASP.NET MVC
I think I am starting to get closer to understanding this all.
I'm trying to get used to using this. Here is what I have so far.
Project
Project.Web (ASP.NET MVC 3.0 RC)
Uses Project.Models
Uses Project.Persistence
Project
Project.Models (Domain Objects)
Membership.Member
Membership.IMembershipProvider
Project
Project.Persistence (Fluent nHibernate)
Uses Project.Models
Uses Castle.Core
Uses Castle.Windsor
Membership.MembershipProvider : IMembershipProvider
I have the following class in Project.Persistence
using Castle.Windsor;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
namespace Project.Persistence
{
public static class IoC
{
private static IWindsorContainer _container;
public static void Initialize()
{
_container = new WindsorContainer()
.Install(
new Persistence.Containers.Installers.RepositoryInstaller()
);
}
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
}
}
namespace Persistence.Containers.Installers
{
public class RepositoryInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component
.For<Membership.IMembershipProvider>()
.ImplementedBy<Membership.MembershipProvider>()
.LifeStyle.Singleton
);
}
}
}
Now, in Project.Web Global.asax Application_Start, I have the following code.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
// Register the Windsor Container
Project.Persistence.IoC.Initialize();
}
Now then, in Project.Web.Controllers.MembershipController I have the following code.
[HttpPost]
public ActionResult Register( Web.Models.Authentication.Registration model)
{
if (ModelState.IsValid)
{
var provider = IoC.Resolve<Membership.IMembershipProvider>();
provider.CreateUser(model.Email, model.Password);
}
// If we got this far, something failed, redisplay form
return View(model);
}
So I am asking first of all..
Am I on the right track?
How can I use Castle.Windsor for my ISessionFactory
I have my SessionFactory working like this ...
namespace Project.Persistence.Factories
{
public sealed class SessionFactoryContainer
{
private static readonly ISessionFactory _instance = CreateSessionFactory();
static SessionFactoryContainer()
{
}
public static ISessionFactory Instance
{
get { return _instance; }
}
private static ISessionFactory CreateSessionFactory()
{
return Persistence.SessionFactory.Map(#"Data Source=.\SQLEXPRESS;Initial Catalog=FluentExample;Integrated Security=true", true);
}
}
}
namespace Project.Persistence
{
public static class SessionFactory
{
public static ISessionFactory Map(string connectionString, bool createSchema)
{
return FluentNHibernate.Cfg.Fluently.Configure()
.Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2008
.ConnectionString(c => c.Is(connectionString)))
.ExposeConfiguration(config =>
{
new NHibernate.Tool.hbm2ddl.SchemaExport(config)
.SetOutputFile("Output.sql")
.Create(/* Output to console */ false, /* Execute script against database */ createSchema);
})
.Mappings(m =>
{
m.FluentMappings.Conventions.Setup(x =>
{
x.AddFromAssemblyOf<Program>();
x.Add(FluentNHibernate.Conventions.Helpers.AutoImport.Never());
});
m.FluentMappings.AddFromAssemblyOf<Mapping.MembershipMap>();
}).BuildSessionFactory();
}
So basically, within my Project.Persistence layer, I call the SessionFactory like this..
var session = SessionFactoryContainer.Instance.OpenSession()
Am I even getting close to doing this right? I'm still confused - I feel like the ISessionFactory should be part of Castle.Windsor, but I can't seem to figure out how to do that. I'm confused also about the way I am creating the Repository in the Controller. Does this mean I have to do all of the 'mapping' each time I use the Repository? That seems like it would be very resource intensive.
Firstly some conceptual details. In an ASP.NET MVC application the typical entry point for a page request is a controller. We want the Inversion of Control container to resolve our controllers for us, because then any dependencies that the controllers have can also be automatically resolved simply by listing the dependencies as arguments in the controllers' constructors.
Confused yet? Here's an example of how you'd use IoC, after it is all set up. I think explaining it this way makes things easier!
public class HomeController : Controller
{
// lets say your home page controller depends upon two providers
private readonly IMembershipProvider membershipProvider;
private readonly IBlogProvider blogProvider;
// constructor, with the dependencies being passed in as arguments
public HomeController(
IMembershipProvider membershipProvider,
IBlogProvider blogProvider)
{
this.membershipProvider = membershipProvider;
this.blogProvider = blogProvider;
}
// so taking your Registration example...
[HttpPost]
public ActionResult Register( Web.Models.Authentication.Registration model)
{
if (ModelState.IsValid)
{
this.membershipProvider.CreateUser(model.Email, model.Password);
}
// If we got this far, something failed, redisplay form
return View(model);
}
}
Note that you have not had to do any resolving yourself, you have just specified in the controller what the dependencies are. Nor have you actually given any indication of how the dependencies are implemented - it's all decoupled. It's very simple there is nothing complicated here :-)
Hopefully at this point you are asking, "but how does the constructor get instantiated?" This is where we start to set up your Castle container, and we do this entirely in the MVC Web project (not Persistence or Domain). Edit the Global.asax file, setting Castle Windsor to act as the controller factory:
protected void Application_Start()
{
//...
ControllerBuilder.Current
.SetControllerFactory(typeof(WindsorControllerFactory));
}
...and define the WindsorControllerFactory so that your controllers are instantiated by Windsor:
/// Use Castle Windsor to create controllers and provide DI
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IWindsorContainer container;
public WindsorControllerFactory()
{
container = ContainerFactory.Current();
}
protected override IController GetControllerInstance(
RequestContext requestContext,
Type controllerType)
{
return (IController)container.Resolve(controllerType);
}
}
The ContainerFactory.Current() method is static singleton that returns a configured Castle Windsor container. The configuration of the container instructs Windsor on how to resolve your application's dependencies. So for example, you might have a container configured to resolve the NHibernate SessionFactory, and your IMembershipProvider.
I like to configure my Castle container using several "installers". Each installer is responsible for a different type of dependency, so I'd have a Controller installer, an NHibernate installer, a Provider installer for example.
Firstly we have the ContainerFactory:
public class ContainerFactory
{
private static IWindsorContainer container;
private static readonly object SyncObject = new object();
public static IWindsorContainer Current()
{
if (container == null)
{
lock (SyncObject)
{
if (container == null)
{
container = new WindsorContainer();
container.Install(new ControllerInstaller());
container.Install(new NHibernateInstaller());
container.Install(new ProviderInstaller());
}
}
}
return container;
}
}
...and then we need each of the installers. The ControllerInstaller first:
public class ControllerInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
AllTypes
.FromAssembly(Assembly.GetExecutingAssembly())
.BasedOn<IController>()
.Configure(c => c.Named(
c.Implementation.Name.ToLowerInvariant()).LifeStyle.PerWebRequest));
}
}
... and here is my NHibernateInstaller although it is different to yours, you can use your own configuration. Note that I'm reusing the same ISessionFactory instance every time one is resolved:
public class NHibernateInstaller : IWindsorInstaller
{
private static ISessionFactory factory;
private static readonly object SyncObject = new object();
public void Install(IWindsorContainer container, IConfigurationStore store)
{
var windsorContainer = container.Register(
Component.For<ISessionFactory>()
.UsingFactoryMethod(SessionFactoryFactory));
}
private static ISessionFactory SessionFactoryFactory()
{
if (factory == null)
{
lock (SyncObject)
{
if (factory == null)
{
var cfg = new Configuration();
factory = cfg.Configure().BuildSessionFactory();
}
}
}
return factory;
}
}
And finally you'll want to define your ProvidersInstaller:
public class ProvidersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
var windsorContainer = container
.Register(
Component
.For<IMembershipProvider>()
.ImplementedBy<SubjectQueries>())
.Register(
Component
.For<IBlogProvider>()
.ImplementedBy<SubjectQueries>());
// ... and any more that your need to register
}
}
This should be enough code to get going! Hopefully you're still with me as the beauty of the Castle container becomes apparent very shortly.
When you define your implementation of your IMembershipProvider in your persistence layer, remember that it has a dependency on the NHibernate ISessionFactory. All you need to do is this:
public class NHMembershipProvider : IMembershipProvider
{
private readonly ISessionFactory sessionFactory;
public NHMembershipProvider(ISessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
}
Note that because Castle Windsor is creating your controllers and the providers passed to your controller constructor, the provider is automatically being passed the ISessionFactory implementation configured in your Windsor container!
You never have to worry about instantiating any dependencies again. Your container does it all automatically for you.
Finally, note that the IMembershipProvider should be defined as part of your domain, as it is defining the interface for how your domain behaviours. As noted above, the implementation of your domain interfaces which deal with databases are added to the persistence layer.
Avoid using a static IoC class like this. By doing this you're using the container as a service locator, so you won't achieve the full decoupling of inversion of control. See this article for further explanations about this.
Also check out Sharp Architecture, which has best practices for ASP.NET MVC, NHibernate and Windsor.
If you have doubts about the lifecycle of the container itself, see Usage of IoC Containers; specifically Windsor