I'm experiencing with .Net Core and I'm currently facing it's DI engine.
My Project is a class library, therefore, asp's binding is irrelevant here.
I followed the tips from this article in order to make DI work.
now, to the juicy part:
I have made a service provider that looks like this:
public static class ServiceProvider
{
public static IServiceProvider GetServiceProvider()
{
var services = new ServiceCollection();
//Singletons
services.AddSingleton<IInstance, Instance>();
//Transients
services.AddTransient<IDate, Date>();
services.AddTransient<IMath, Math>();
services.AddTransient<INumber, Number>();
return services.BuildServiceProvider();
}
}
I have then tried executing it in a static class that looks like this:
public static class MySingleton
{
public static IInstance Instance
=> ServiceProvider.GetServiceProvider().GetService<IInstance>();
}
and in order to test the singleton behavior, I have tested it like this:
[Test]
public void Instance_HundredTimes_ReturnsSameInstance()
{
//Arrange
const int callCount = 100;
var results = new IInstance[callCount];
//Act
for (var i = 0; i < callCount; i++)
{
results[i] = MySingleton.Instance;
}
//Assert
Assert.That(results.Distinct().Count(), Is.EqualTo(1));
}
the test results came back negative and instead of having a single reference after the distinct (cause it is a singleton) I'm still left with a hundred instances.
am I doing anything wrong?
did I miss anything in configuration?
Your problem is in this code block:
public static class MySingleton
{
public static IInstance Instance
=> ServiceProvider.GetServiceProvider().GetService<IInstance>();
}
What you are doing here is to call ServiceProvider.GetServiceProvider().GetService<IInstance>() each time you access the property. That means do not actually have a singleton. What you want to do is to set the singleton instance once:
public static class MySingleton
{
public static IInstance Instance
{
get;
} = ServiceProvider.GetServiceProvider().GetService<IInstance>();
}
Additionally, you have a similar problem when you create your services. You create a new ServiceCollection each time you call GetServiceProvider(). You probably don't want that. You probably want something like this:
public static class ServiceProvider
{
private static IServiceProvider serviceProvider = null;
public static IServiceProvider GetServiceProvider()
{
if (serviceProvider == null)
{
var services = new ServiceCollection();
//Singletons
services.AddSingleton<IInstance, Instance>();
//Transients
services.AddTransient<IDate, Date>();
services.AddTransient<IMath, Math>();
services.AddTransient<INumber, Number>();
serviceProvider = services.BuildServiceProvider();
}
return serviceProvider;
}
}
Problem:
My problem laid in not keeping my IserviceProvider instance in MySingleton
Solution:
TL;DR
have a static instance of IserviceProvider
Code Refactor
refactor ServiceProvider to Look as following:
public class LodashServiceProvider
{
private static readonly Lazy LazyServiceProvider;
static LodashServiceProvider()
{
LazyServiceProvider = new Lazy<IServiceProvider>(InitializeServiceProvider);
}
public static IServiceProvider GetServiceProvider() => LazyServiceProvider.Value;
private static IServiceProvider InitializeServiceProvider()
{
var services = new ServiceCollection();
//Singletons
services.AddSingleton<ILodashInstance, LodashInstance>();
//Transients
services.AddTransient<ILodashDate, LodashDate>();
services.AddTransient<ILodashMath, LodashMath>();
services.AddTransient<ILodashNumber, LodashNumber>();
return services.BuildServiceProvider();
}
}
I'd like to thank Kiziu & Sefe for their solutions to the question.
Related
I have RegisterMessageHandlers that register message handler per message name.
I want to automatically find and register all handlers through reflection. I can annotate each message with MessageAttribute (like shown below) and get the message name through reflection as well. The problem is when I want to instantiate a handler via Activator I have to provide all the dependencies in the constructor.
My solution is to register all instances with DI and pass IServiceProvider to MainManagerClass(IServiceProvider provider) and then use ActivatorUtilities.CreateInstance(handlerType) to instantiate each discovered handler through reflection.
But, then I read that there is DI and service locator which is antipattern and it's not very clear when one becomes the other.
So, I think I need a DI in order to accomplish what I want. Or do I?
public class MainManagerClass
{
private Dictionary<string, MessageHandler> _handlers;
private void RegisterMessageHandlers()
{
_messageHandlers["msg1"] = new MessageHandler1(new Service1());
_messageHandlers["msg2"] = new MessageHandler2(new Service1(), new Service2());
}
}
public class MessageHandler1 : MessageHandler<Message1>
{
public MessageHandler1(IService1 service){}
}
public class MessageHandler2 : MessageHandler<Message2>
{
public MessageHandler1(IService1 service1, IService2 service2){}
}
public abstract class MessageHandler<T> : MessageHandler
{
}
public abstract class MessageHandler
{
}
[Message("msg1")]
public class Message1
{
}
UPDATE
public class MainManagerClass
{
private Dictionary<string, MessageHandler> _handlers;
private readonly IServiceProvider _serviceProvider;
public MainManagerClass(IServiceProvider serviceProvider)
{
}
private void RegisterMessageHandlers()
{
var messageHandlers = Assembly.GetCallingAssembly()
.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(MessageHandler))).ToList();
foreach (var handler in messageHandlers)
{
var messageType = handler.BaseType.GenericTypeArguments[0];
var msgAttribute = messageType.CustomAttributes
.Where(t => t.AttributeType == typeof(MessageAttribute))
.FirstOrDefault();
if (msgAttribute == null)
throw new Exception($"Message name not defined for message type {messageType.Name}");
var msgName = msgAttribute.ConstructorArguments[0].Value.ToString();
_messageHandlers[msgName] = ActivatorUtilities.CreateInstance(_serviceProvider, handler) as MessageHandler;
}
}
}
internal class Program
{
static async Task Main(string[] args)
{
var host = CreateHostBuilder().Build();
var manager = new MainManagerClass(host.Services);
...
}
private static IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((_, services) =>
{
services
.AddSingleton<IService1, Service1>()
.AddSingleton<IService2, Service2>()
.AddSingleton<IService3, Service3>()
;
});
}
}
If you don't want to add interface and keep abstract class as in your example - you can register your handlers like that:
builder.Services.AddTransient<MessageHandler<Message1>, MessageHandler1>();
builder.Services.AddTransient<MessageHandler<Message2>, MessageHandler2>();
And then if you inject MessageHandler<Message1> in your controller for instance, MessageHandler1 will be resolved as well as other dependencies (IService1 in your case).
I think I still don't get your question but I hope this will be helpfull for you. Anyway, I followed Jaroslav's answer and your comment to create MessageHandlerFactory object then I changed your code a bit to cover both scenarios but you need the message type to resolve its handler from the service provider plus, If you want to register all handlers automatically, you should use reflection at startup, find all objects that inherit from IMessageHandler<T>, and register them to DI or use packages like Scrutor.
public class MessageHandlerFactory
{
private IServiceProvider _serviceProvider;
public IMessageHandler<T> ResolveHandler<T>()
{
return _serviceProvider.GetRequiredService<IMessageHandler<T>>();
}
}
public class MessageHandler1 : IMessageHandler<Message1>
{
public MessageHandler1(IService1 service){}
}
public class MessageHandler2 : IMessageHandler<Message2>
{
public MessageHandler2(IService1 service1, IService2 service2){}
}
public interface IMessageHandler<T>
{
}
public class Message1
{
}
public class Message2
{
}
builder.Services.AddScoped<IMessageHandler<Message1>, MessageHandler1>();
builder.Services.AddScoped<IMessageHandler<Message2>, MessageHandler2>();
I'm trying to resolve an interface that I registered in Autofac but it seems to be not working. There is
nullreferenceexception.
Class where I register the inferface :
public void RegisterAutofac(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
(...)
builder.RegisterType<ApiFileTester>().As<IApiFlTester>().InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
Then I want to use it in a class :
public class ApiFileSendingController : ApiClientBase
{
private readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester) : base(dto)
{
_tester = tester;
}
public void Send(List<AftInvFileDTO> filesToSendRetry = null)
{
_apiFileTester.RegisterTestingMethods();
}
}
Then in some other class:
DTO dto = new DTO(); //some configuration here
ApiFileSendingController sender = new ApiFileSendingController(dto, null);
sender.Send();
There is a problem here because my interface is null. I've tried to pass it like this:
ApiFileSendingController sender = new ApiFileSendingController(dto,
null);
but it's null and it's completely reasonable (I am passing the null).
IS it possible to configure optional parameter or something? I'd like to have this interface resolved automatically by autofac, not manually.
I don't seem to have a problem resolving your class. Technically it's impossible to really answer your question since the code won't even compile and it appears you have a ton of missing autofac registrations.
Working Example.
// #nuget: Autofac
using System;
using Autofac;
public class Program
{
private static IContainer _container;
public static void Main()
{
RegisterAutofac();
using (var httpRequestScope = _container.BeginLifetimeScope("AutofacWebRequest"))
{
var apiController = httpRequestScope.Resolve<ApiFileSendingController>();
Console.WriteLine(apiController._apiFileTester);
}
}
public static void RegisterAutofac()
{
var builder = new ContainerBuilder();
//builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<ApiFileTester>().As<IApiFlTester>().InstancePerLifetimeScope();
builder.RegisterType<ApiFileSendingController>().AsSelf();
builder.RegisterType<DTO>().AsSelf();
_container = builder.Build();
}
public class ApiFileSendingController : ApiClientBase
{
public readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester): base (dto)
{
_apiFileTester = tester;
}
}
public interface IApiFlTester { }
public class ApiFileTester : IApiFlTester { }
public class ApiClientBase
{
public ApiClientBase(DTO dto)
{
}
}
public class DTO { }
}
You have misconception at Autofac DI, most of the DI frameworks are good at creating instances for you, via constructor injection and property injection you will get the instance with their dependencies automatically wired up.
Your constructor contains DTO instance which you will provide during runtime, Autofac will not resolve that since you had not declare it to the DI container during ConfigureServices cycle.
You might need to giving up using Autofac in this case to get the freedom of creating controller instance at your own code, you will need to get the concrete class instance from Reflection instead. The abstraction / implementation isolation is still there via this approach.
public class ApiFileSendingController : ApiClientBase
{
private readonly IApiFlTester _apiFileTester;
public ApiFileSendingController(DTO dto, IApiFlTester tester) : base(dto)
{
if (tester is null)
_tester = GetApiTesterViaReflection();
else
_tester = tester;
}
public ApiFileSendingController(DTO dto) : base(dto)
{
_apiFileTester = GetApiTesterViaReflection();
}
public void Send(List<AftInvFileDTO> filesToSendRetry = null)
{
_apiFileTester.RegisterTestingMethods();
}
private IApiFlTester GetApiTesterViaReflection()
{
Type type = typeof(IApiFlTester).Assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IApiFlTester))).FirstOrDefault();
return Activator.CreateInstance(type) as IApiFlTester;
}
}
I'm very new to using Unity.
I'm trying to test a segment of code in LINQPad. This code uses a DBContext which relies on Log4Net as a service. I'm trying to write the sample code to use the actual DBContext, but can't get it to construct.
The code I'm trying is below. If there is more information needed, please ask for it before down-voting, since I'm not sure how much you need to see to understand my issue, since I'm still learning Unity.
void Main()
{
RegisterObjects();
var logger = IoCHelper.Resolve<ILogger>();
//var _logger = new Clark.Logging.MultiLogger();
var _logger = logger;
var _ediContext = new EdiContext();
var transactionId = 1008;
var limit = 0;
var temp = new Type210SubscriberProvider(_ediContext)
.GetAfterNew(transactionId, limit);
temp.Dump();
var temp2 = new Type210SubscriberProvider(_ediContext)
.GetAfter(transactionId, limit);
temp2.Dump();
}
public void RegisterObjects()
{
XmlConfigurator.Configure();
var multiLogger = new MultiLogger();
multiLogger.Register(new Log4NetLogger());
IoCHelper.RegisterInstance<ILogger>(multiLogger);
}
If I try just this:
void Main()
{
var _ediContext = new EdiContext();
}
The error message I am receiving in LINQPad is:
Resolution of the dependency failed, type = "Clark.Logging.ILogger", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, Clark.Logging.ILogger, is an interface and cannot be constructed. Are you missing a type mapping?
At the time of the exception, the container was:
Resolving Clark.Logging.ILogger,(none)
UPDATE:
Here is some more detail from the Global.asax.cs file. I'm not sure how to translate this to LINQPad.
protected void Application_Start()
{
// GlobalConfiguration.Configuration is an HttpConfiguration object.
ConfigureContainer(GlobalConfiguration.Configuration);
ConfigureServices(GlobalConfiguration.Configuration);
}
private static void ConfigureServices(HttpConfiguration configuration)
{
configuration.Services.Add(typeof (IExceptionLogger), new UnhandledExceptionLogger(GetLogger()));
configuration.Services.Replace(typeof (IExceptionHandler), new UnhandledExceptionHandler());
}
private static void ConfigureContainer(HttpConfiguration config)
{
config.DependencyResolver = new IoCContainer(IoCHelper.Container);
new LoggingDependencyInitializer().RegisterObjects();
IoCHelper.RegisterType<IEdiContext>(new InjectionFactory(unityContainer => new EdiContext()));
IoCHelper.RegisterType<SubscriberController>();
IoCHelper.RegisterType<ConsumerInformationController>();
IoCHelper.RegisterType<TransactionTypeController>();
}
private static ILogger GetLogger()
{
return IoCHelper.Resolve<ILogger>();
}
Here is the IoCHelper class:
public static class IoCHelper
{
private static UnityContainer _container;
public static UnityContainer Container
{
get { return _container ?? (_container = new UnityContainer()); }
}
public static T Resolve<T>()
{
return Container.Resolve<T>();
}
public static void RegisterType<TFrom, TTo>() where TTo : TFrom
{
Container.RegisterType<TFrom, TTo>();
}
public static void RegisterInstance(Type type, object instance)
{
Container.RegisterInstance(type, instance);
}
public static void RegisterType<T>()
{
Container.RegisterType<T>();
}
public static void RegisterInstance<T>(T instance)
{
Container.RegisterInstance(instance);
}
public static void RegisterType<T>(InjectionFactory injectionFactory)
{
Container.RegisterType<T>(injectionFactory);
}
}
When using an IOC container, you need to register your types (e.g. map interfaces \ abstract classes into their real types). Since when you want the container to resolve an interface, it will want to find it's mapping before providing the instance.
BTW, if Unity doesn't find a map, it will try to construct the type. In your case it fails since you cannot construct an interface.
With Unity, you can do it either by configuration using:
var section = ConfigurationManager.GetSection(SectionName) as UnityConfigurationSection;
if (section != null)
{
section.Configure(container);
}
Or directly:
container.RegisterType<InterfaceType, ConcreteType>();
Since I see this code line in your example:
IoCHelper.RegisterInstance<ILogger>(multiLogger);
You are registering ILogger with a specific instance. There must be a problem with your IoCHelper implementation. Please add more code and I'll edit my answer with a specific solution.
I'm using lambda expression in order to register my component like this
var builder = new ContainerBuilder();
builder.RegisterType<EndPointServiceClient>().As<IEndPointService>();
builder.Register(imp => new EndPointImp(imp.Resolve<IEndPointService>())).As<IEndPointImp>();
builder.Register(log => new Login(LoginEnumType.EmployeeLogin, log.Resolve<IEndPointImp>()));
at the application start I resolve and instance of the login class which is a win form class
Login loginWindow = container.Resolve<Login>();
Application.Run(loginWindow);
but for some reason whenever I inspect the value of imp I find it set to null
public Login(LoginEnumType loginType, IEndPointImp imp)
{
_loginType = loginType;
_imp = imp;
InitializeComponent();
}
would anyone have an idea what I'm doing wrong over here?
I'm not entirely sure why your instance is not working. I have used the code from your example and mocked this up with the code below, and it is indeed all working for me. I am resolved an instance of the Login class and imp is injected with an instance of IEndPointImp from the container.
Perhaps there is something from my example code below which you may have missed and might help you?
void Main()
{
DependencyConfig.Configure();
var loginWindow = DependencyConfig.Container.Resolve<Login>();
}
public class DependencyConfig
{
public static IContainer Container { get; private set;}
public static void Configure()
{
var builder = new ContainerBuilder();
builder.RegisterType<EndPointServiceClient>().As<IEndPointService>();
builder.Register(imp => new EndPointImp(imp.Resolve<IEndPointService>())).As<IEndPointImp>();
builder.Register(log => new Login(LoginEnumType.EmployeeLogin, log.Resolve<IEndPointImp>()));
Container = builder.Build();
}
}
public enum LoginEnumType
{
EmployeeLogin
}
public interface IEndPointService
{
}
public class EndPointServiceClient : IEndPointService
{
}
public interface IEndPointImp
{
}
public class EndPointImp : IEndPointImp
{
private readonly IEndPointService _endPointService;
public EndPointImp(IEndPointService endPointService)
{
_endPointService = endPointService;
}
}
public class Login
{
private readonly LoginEnumType _loginType;
private readonly IEndPointImp _imp;
public Login(LoginEnumType loginType, IEndPointImp imp)
{
_loginType = loginType;
_imp = imp;
}
}
I'm wondering how to properly use abstract factories when using a DI framework and one of the parameters in that factory is a dependency that should be handled by the DI framework.
I am not sure whether to make my abstract factory omit the parameter completely then use my DI container to wire it up or whether I should pass the dependency to the object.
For example, I have a TcpServer and it uses a Session.Factory to create sockets. The Session object actually takes a Processor in its constructor. Should I pass the Processor to the TcpServer then have it pass it onto the Session.Factory or have my DI container do the wiring?
If I were to have the DI container do the wiring it would look like this:
class Session : ISession
{
public delegate ISession Factory(string name);
...
public Session(string name, Processor processor)
{
...
}
}
class TcpServer : ITcpServer
{
private readonly Session.Factory _sessionFactory;
public TcpServer(Session.Factory sessionFactory)
{
this._sessionFactory = socketFactory;
}
...
public void OnConnectionReceived()
{
...
var session= _sessionFactory(ip.LocalEndPoint());
...
}
}
Then using a DI container like Ninject I'd be able to do this when configuring the container:
Bind<Session.Factory>().ToMethod(c =>
{
var processor = Kernel.Get<Processor>();
return (name) => new Session(name, processor);
}).InSingletonScope();
My main issue with this approach is that it assumes whoever creates the Session.Factory knows about the processor. In my case, since I am using a DI container, this is actually very convenient but it seems weird to have a factory have its own dependencies. I always imagined a factory not really ever having any members.
If I were to pass the dependency through
class Session : ISession
{
public delegate ISession Factory(string name, Processor processor);
...
public Session(string name, Processor processor)
{
...
}
}
class TcpServer : ITcpServer
{
private readonly Session.Factory _sessionFactory;
private readonly Processor _processor;
public TcpServer(Session.Factory sessionFactory, Processor processor)
{
this._processor = processor;
}
...
public void OnConnectionReceived()
{
...
var session = _sessionFactory(ip.LocalEndPoint(), _processor);
...
}
}
I have two issues with the second approach:
The TcpServer doesn't actually do anything with the Processor. It just passes it along. Seems like this is poor man's DI at work almost.
In the real program behind this code, the Processor actually has a reference to the TcpServer. Therefore when using this approach, I get a circular reference. When I break it apart by using the first scenario then it's not an issue.
What do you think is the best approach? I am open to new ideas as well.
Thanks!
Many containers support factories in one or another way and this is the way you should go.
E.g. Taking your example define a ISessionFactory interface like this
public interface ISessionFactory
{
ISession CreateSession(string name);
}
For Ninject 2.3 see https://github.com/ninject/ninject.extensions.factory and let it be implemented by Ninject
Bind<ISessionFactory>().AsFactory();
For 2.2 do the implementation yourself
public class SessionFactory : ISessionFactory
{
private IKernel kernel;
public SessionFactory(IKernel kernel)
{
this.kernel = kernel;
}
public ISession CreateSession(string name)
{
return this.kernel.Get<ISession>(new ConstructorArgument("name", name));
}
}
The pattern I use for an abstract factory pattern is a little different from yours. I use something like setter injection on a generic singleton, but wrap the configurable delegate "property" in a more intuitive interface.
I would prefer not to have to register each implementation individually, so I would prefer to use some convention that can be tested at application start up. I'm not sure about the Ninject syntax for autoregistering custom conventions, but the logic would come down to scanning the relevant assemblies for reference types, T, that have static readonly fields of type AbstractFactory<T>, then calling Configure(Func<T>) on that static member using reflection.
An example of the generic abstract factory singleton and how it would be declared on a Session is below.
public class Session {
public static readonly AbstractFactory<Session> Factory = AbstractFactory<Session>.GetInstance();
}
public sealed class AbstractFactory<T>
where T: class{
static AbstractFactory(){
Bolt = new object();
}
private static readonly object Bolt;
private static AbstractFactory<T> Instance;
public static AbstractFactory<T> GetInstance(){
if(Instance == null){
lock(Bolt){
if(Instance == null)
Instance = new AbstractFactory<T>();
}
}
return Instance;
}
private AbstractFactory(){}
private Func<T> m_FactoryMethod;
public void Configure(Func<T> factoryMethod){
m_FactoryMethod = factoryMethod;
}
public T Create() {
if(m_FactoryMethod == null) {
throw new NotImplementedException();
}
return m_FactoryMethod.Invoke();
}
}
Update
If you need to pass parameters into your factory method, then you can alter the class such as:
public sealed class AbstractFactory<TDataContract,T>
where T: class{
static AbstractFactory(){
Bolt = new object();
}
private static readonly object Bolt;
private static AbstractFactory<TDataContract,T> Instance;
public static AbstractFactory<TDataContract,T> GetInstance(){
if(Instance == null){
lock(Bolt){
if(Instance == null)
Instance = new AbstractFactory<T>();
}
}
return Instance;
}
private AbstractFactory(){}
private Func<TDataContract,T> m_FactoryMethod;
public void Configure(Func<TDataContract,T> factoryMethod){
m_FactoryMethod = factoryMethod;
}
public T Create(TDataContract data) {
if(m_FactoryMethod == null) {
throw new NotImplementedException();
}
return m_FactoryMethod.Invoke(data);
}
}
Your SessionData, Session and TcpServer might look like
public class SessionData{
public DateTime Start { get; set; }
public string IpAddress { get; set; }
}
public class Session {
public static readonly AbstractFactory<SessionData,Session> Factory = AbstractFactory<Session>.GetInstance();
private readonly string _ip;
private readonly DateTime _start;
public Session(SessionData data) {
_ip = data.IpAddress;
_start = DateTime.Now;
}
public event EventHandler<RequestReceivedEventEventArgs> RequestAdded;
}
public class RequestReceivedEventArgs: EventArgs {
public SessionRequest Request { get; set; }
}
public class TcpServer : ITcpServer
{
private readonly Processor _processor;
public TcpServer(Processor processor)
{
this._processor = processor;
}
public void OnConnectionReceived()
{
var sessionData = new SessionData {
IpAddress = ip.LocalEndPoint(),
Start = DateTime.Now
};
var session = Session.Factory.Create(sessionData);
//...do other stuff
}
public void ServeResponse(SessionRequest request){
_processor.Process(request);
}
}
When configuring your DI container, you can set up the factory such as:
Session.Factory.Configure(sessionData => {
// instead of injecting the processor into the Session, configure events
// that allow the TcpServer to process the data.
// (After all, it is more logical for a servers to serve a request than
// it is for a Session to do the Processing. Session's tend to store data
// and state, not invoke processes
session.RequestAdded += (sender,e) => {
Kernel.Get<ITcpServer>.ServeResponse(e.Request);
};
});