Ninject and Using with Disposable Object (Resetting the object properties) - c#

I had a class before I introduced dependency inject that looked like this:
public class Widget
{
public Widget Create()
{
using (DataProvider dataProvider = new DataProvder())
{
dataProvider.AddInput("name", name);
dataProvider.AddInput("path", path);
dataProvider.AddInput("dateCreated", DateTime.UtcNow);
using (var reader = _dataProvider.ExecuteReader("usp_widget_create"))
{
reader.Read();
return new Widget(reader);
}
}
}
}
Then I introduced dependency inject using Ninject and my class now looks like this so I don't create a dependency to the DataProvider class.
public class Widget
{
IDataProvider _dataProvider;
public Widget(IDataProvider dataProvider)
{
_dataProvider = dataProvider;
}
public Widget Create()
{
_dataProvider.AddInput("name", name);
_dataProvider.AddInput("path", path);
_dataProvider.AddInput("dateCreated", DateTime.UtcNow);
using (var reader = _dataProvider.ExecuteReader("usp_widget_create"))
{
reader.Read();
return new Widget(reader);
}
}
}
The problem with the new class is that one, the DataProvider won't get disposed and two, the properties of the DataProvider won't be reset. So if I call Create from the same object twice it will duplicate the parameters and throw an exception. I know I can explicitly fix the second issue by clearing the parameters, but I feel like there must be a more universal approach and I am missing something.
How should this situation be resolved?

The pattern that very much you want to utilize is the Dependency Injection with Abstract Factory Pattern.
This factory pattern allows you dynamically create instances whenever you required. And it is a very common thing to do so.
Define a Factory that allows you to create Provide instances.
public interface IProviderFactory
{
T Create<T>();
}
The implementation can be simple as below.
public class ProviderFactory : IProviderFactory
{
private readonly IKernel _kernel;
public ProviderFactory(IKernel kernel)
{
_kernel = kernel;
}
public T Create<T>()
{
var instance = _kernel.Get<T>();
return instance;
}
}
Now change your Widget to accept the Factory instead of the IDataProvider
public class Widget
{
readonly IProviderFactory _factory;
public Widget(IProviderFactory factory)
{
_factory = factory;
}
public Widget Create()
{
var provider = _factory.Create<IDataProvider>();
provider.AddInput("name", "name");
provider.AddInput("path", "path");
provider.AddInput("dateCreated", DateTime.UtcNow);
//.....
}
}
Note that each invocation of Create() would resolve a new instance of the IDataProvider.
var provider = _factory.Create();
The Kernal Registration is something like below..
using (IKernel Kernel = new StandardKernel())
{
Kernel.Bind<IDataProvider>().To<DataProvider>();
Kernel.Bind<IProviderFactory>()
.To<ProviderFactory>().WithConstructorArgument(typeof(IKernel), Kernel);
var widget = Kernel.Get<Widget>();
widget.Create();
widget.Create();
}
Something along line should provide you the direction to a possible solution.

Related

How to resolve an interface and use it in the class using Autofac

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;
}
}

How do I set up dependency injection if my concrete class requires simple data type in addition to other interface(s)?

If I have a class structure like below:
public interface IDataProvider
{
object GetSomeData(int id);
}
public class InMemoryDataProvider : IDataProvider
{
public InMemoryDataProvider(string connString)
{
}
public object GetSomeData(int id)
{
return new object();
}
}
public interface IAnimal
{
string GetName();
}
public class Dog: IAnimal
{
public Dog(string someRequiredInfo, IDataProvider someDataProvider)
{
}
public string GetName()
{
return string.Empty;
}
}
I am trying to set up DI chain using default DI container that comes with asp.net core MVC. But I don't understand how to set up for my scenario. I am new to using DI container so I could be missing some fundamental idea.Below is how I tried to set it up (unsuccessfully):
string connString = "connectionString";
someString = "some required info";
AddSingleton<IDataProvider, InMemoryDataProvider>(x => new InMemoryDataProvider(connString));
AddTransient<IAnimal, Dog>(); //if I do this, how will it get the first parameter of someString? Don't think this will even work.
AddTransient<IAnimal, Dog>(x => new Dog(someString, IDataProvider???)) //how to do this?
Also, I want the data provider to be a singleton and that eliminates the possibility of doing like below isn't it?
services.AddTransient<IAnimal, Dog>(x => new Dog(someString, new InMemoryDataProvider(connString)));
You need to change your code in yout Startup.cs to the snippet below.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddSingleton(x => new InMemoryDataProvider(connString));
services.AddSingleton<IDataProvider, InMemoryDataProvider>(x => x.GetService<InMemoryDataProvider>());
services.AddSingleton<IAnimal, Dog>(d=> new Dog(someString, d.GetService<IDataProvider>()));
services.AddMvc();
}
And just inject IAnimal into your Controllers constructor like so:
public ValuesController(IAnimal animal)
{
_animal = animal;
}

How can I pass a runtime parameter as part of the dependency resolution?

I need to be able to pass a connection string into some of my service implementations. I am doing this in the constructor. The connection string is configurable by user will be added the ClaimsPrincipal as a Claim.
All fine so far.
Unfortunately, I also want to be able to use the dependency injection features in ASP.NET Core to the fullest and resolve the service implementation though DI.
I have a POC implmentation:
public interface IRootService
{
INestedService NestedService { get; set; }
void DoSomething();
}
public class RootService : IRootService
{
public INestedService NestedService { get; set; }
public RootService(INestedService nestedService)
{
NestedService = nestedService;
}
public void DoSomething()
{
// implement
}
}
public interface INestedService
{
string ConnectionString { get; set; }
void DoSomethingElse();
}
public class NestedService : INestedService
{
public string ConnectionString { get; set; }
public NestedService(string connectionString)
{
ConnectionString = connectionString;
}
public void DoSomethingElse()
{
// implement
}
}
These services have been registered during startup and INestedService has been added the constructor of a controller.
public HomeController(INestedService nestedService)
{
NestedService = nestedService;
}
As expected, I get the error Unable to resolve service for type 'System.String' while attempting to activate 'Test.Dependency.Services.NestedService'.
What are my options here?
To pass a runtime parameter not known at the start of the application, you have to use the factory pattern. You have two options here:
factory class (similar to how IHttpClientFactory is implemented)
public class RootService : IRootService
{
public RootService(INestedService nested, IOtherService other)
{
// ...
}
}
public class RootServiceFactory : IRootServiceFactory
{
// in case you need other dependencies, that can be resolved by DI
private readonly IServiceProvider services;
public RootServiceFactory(IServiceProvider services)
{
this.services = services;
}
public IRootService CreateInstance(string connectionString)
{
// instantiate service that needs runtime parameter
var nestedService = new NestedService(connectionString);
// note that in this example, RootService also has a dependency on
// IOtherService - ActivatorUtilities.CreateInstance will automagically
// resolve that dependency, and any others not explicitly provided, from
// the specified IServiceProvider
return ActivatorUtilities.CreateInstance<RootService>(services,
new object[] { nestedService, });
}
}
and inject IRootServiceFactory instead of your IRootService
IRootService rootService = rootServiceFactory.CreateInstance(connectionString);
factory method
services.AddTransient<Func<string,INestedService>>((provider) =>
{
return new Func<string,INestedService>(
(connectionString) => new NestedService(connectionString)
);
});
and inject the factory method into your service instead of INestedService
public class RootService : IRootService
{
public INestedService NestedService { get; set; }
public RootService(Func<string,INestedService> nestedServiceFactory)
{
NestedService = nestedServiceFactory("ConnectionStringHere");
}
public void DoSomething()
{
// implement
}
}
or resolve it per call
public class RootService : IRootService
{
public Func<string,INestedService> NestedServiceFactory { get; set; }
public RootService(Func<string,INestedService> nestedServiceFactory)
{
NestedServiceFactory = nestedServiceFactory;
}
public void DoSomething(string connectionString)
{
var nestedService = nestedServiceFactory(connectionString);
// implement
}
}
Simple configuration
public void ConfigureServices(IServiceCollection services)
{
// Choose Scope, Singleton or Transient method
services.AddSingleton<IRootService, RootService>();
services.AddSingleton<INestedService, NestedService>(serviceProvider=>
{
return new NestedService("someConnectionString");
});
}
With appSettings.json
If you decide to hide your connection string inside appSettings.json, e.g:
"Data": {
"ConnectionString": "someConnectionString"
}
Then provided that you've loaded your appSettings.json in the ConfigurationBuilder (usually located in the constructor of the Startup class), then your ConfigureServices would look like this:
public void ConfigureServices(IServiceCollection services)
{
// Choose Scope, Singleton or Transient method
services.AddSingleton<IRootService, RootService>();
services.AddSingleton<INestedService, NestedService>(serviceProvider=>
{
var connectionString = Configuration["Data:ConnectionString"];
return new NestedService(connectionString);
});
}
With extension methods
namespace Microsoft.Extensions.DependencyInjection
{
public static class RootServiceExtensions //you can pick a better name
{
//again pick a better name
public static IServiceCollection AddRootServices(this IServiceCollection services, string connectionString)
{
// Choose Scope, Singleton or Transient method
services.AddSingleton<IRootService, RootService>();
services.AddSingleton<INestedService, NestedService>(_ =>
new NestedService(connectionString));
}
}
}
Then your ConfigureServices method would look like this
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration["Data:ConnectionString"];
services.AddRootServices(connectionString);
}
With options builder
Should you need more parameters, you can go a step further and create an options class which you pass to RootService's constructor. If it becomes complex, you can use the Builder pattern.
I devised this little pattern to help me resolve objects that require runtime parameters ,but also have dependencies which the DI container is able to resolve - I implemented this using the MS DI Container for a WPF App.
I already had a Service Locator (yes I know its a code smell - but I attempt to resolve that by the end of the example) that I used in specific scenarios to get access to objects in the DIC:
public interface IServiceFactory
{
T Get<T>();
}
Its implementation takes a func<> in the constructor to decouple the fact it relies on MS DI.
public class ServiceFactory : IServiceFactory
{
private readonly Func<Type, object> factory;
public ServiceFactory(Func<Type, object> factory)
{
this.factory = factory;
}
// Get an object of type T where T is usually an interface
public T Get<T>()
{
return (T)factory(typeof(T));
}
}
This was created in the composition root like so:
services.AddSingleton<IServiceFactory>(provider => new ServiceFactory(provider.GetService));
This pattern was extended to not only 'Get' objects of type T, but 'Create' objects of type T with parameters P:
public interface IServiceFactory
{
T Get<T>();
T Create<T>(params object[] p);
}
The implementation took another func<> to decouple the creation mechanism:
public class ServiceFactory : IServiceFactory
{
private readonly Func<Type, object> factory;
private readonly Func<Type, object[], object> creator;
public ServiceFactory(Func<Type, object> factory, Func<Type, object[], object> creator)
{
this.factory = factory;
this.creator = creator;
}
// Get an object of type T where T is usually an interface
public T Get<T>()
{
return (T)factory(typeof(T));
}
// Create (an obviously transient) object of type T, with runtime parameters 'p'
public T Create<T>(params object[] p)
{
IService<T> lookup = Get<IService<T>>();
return (T)creator(lookup.Type(), p);
}
}
The creation mechanism for the MS DI container is in the ActivatorUtilities extensions, here's the updated composition root:
services.AddSingleton<IServiceFactory>(
provider => new ServiceFactory(
provider.GetService,
(T, P) => ActivatorUtilities.CreateInstance(provider, T, P)));
Now that we can create objects the problem becomes we have no way of determining the type of object we need without the DI container actually creating an object of that type, which is where the IService interface comes in:
public interface IService<I>
{
// Returns mapped type for this I
Type Type();
}
This is used to determine what type we are trying to create, without actually creating the type, its implementation is:
public class Service<I, T> : IService<I>
{
public Type Type()
{
return typeof(T);
}
}
So to pull it all together, in your composition root you can have objects that don't have runtime parameters which can be resolved by 'Get' and ones which do resolved by 'Create' e.g.:
services.AddSingleton<ICategorySelectionVM, CategorySelectionVM>();
services.AddSingleton<IService<ISubCategorySelectionVM>, Service<ISubCategorySelectionVM, SubCategorySelectionVM>>();
services.AddSingleton<ILogger, Logger>();
The CategorySelectionVM has only dependencies that can be resolved via the DIC:
public CategorySelectionVM(ILogger logger) // constructor
And this can be created by anyone with a dependency on the service factory like:
public MainWindowVM(IServiceFactory serviceFactory) // constructor
{
}
private void OnHomeEvent()
{
CurrentView = serviceFactory.Get<ICategorySelectionVM>();
}
Where as the SubCategorySelectionVM has both dependencies that the DIC can resolve, and dependencies only known at runtime:
public SubCategorySelectionVM(ILogger logger, Category c) // constructor
And these can be created like so:
private void OnCategorySelectedEvent(Category category)
{
CurrentView = serviceFactory.Create<ISubCategorySelectionVM>(category);
}
Update : I just wanted to add a little enhancement which avoided using the service factory like a service locator, so I created a generic service factory which could only resolve objects of type B:
public interface IServiceFactory<B>
{
T Get<T>() where T : B;
T Create<T>(params object[] p) where T : B;
}
The implementation of this depends on the original service factory which could resolve objects of any type:
public class ServiceFactory<B> : IServiceFactory<B>
{
private readonly IServiceFactory serviceFactory;
public ServiceFactory(IServiceFactory serviceFactory)
{
this.serviceFactory = serviceFactory;
}
public T Get<T>() where T : B
{
return serviceFactory.Get<T>();
}
public T Create<T>(params object[] p) where T : B
{
return serviceFactory.Create<T>(p);
}
}
The composition root adds the original service factory for all the generic typed factories to depend on, and any of the typed factories:
services.AddSingleton<IServiceFactory>(provider => new ServiceFactory(provider.GetService, (T, P) => ActivatorUtilities.CreateInstance(provider, T, P)));
services.AddSingleton<IServiceFactory<BaseVM>, ServiceFactory<BaseVM>>();
Now our main view model can be restricted to creating only objects that derive from BaseVM:
public MainWindowVM(IServiceFactory<BaseVM> viewModelFactory)
{
this.viewModelFactory = viewModelFactory;
}
private void OnCategorySelectedEvent(Category category)
{
CurrentView = viewModelFactory.Create<SubCategorySelectionVM>(category);
}
private void OnHomeEvent()
{
CurrentView = viewModelFactory.Get<CategorySelectionVM>();
}
I know this is a bit old but thought i'd give my input since there is a easier way to do this in my opinion. This doesn't cover all the cases as shown in other posts. But this is a easy way of doing it.
public class MySingleton {
public MySingleton(string s, int i, bool b){
...
}
}
No lets create a service extention class to add easier and keep it neet
public static class ServiceCollectionExtentions
{
public static IServiceCollection RegisterSingleton(this IServiceCollection services, string s, int i, bool b) =>
services.AddSingleton(new MySingleton(s, i, b));
}
Now to call it from startup
services.RegisterSingleton("s", 1, true);
IMHO, follow the options pattern. Define a strong type to hold your connection string, then an IConfigureOptions<T> to configure it from your user claim.
public class ConnectionString {
public string Value { get; set; }
}
public class ConfigureConnection : IConfigureOptions<ConnectionString> {
private readonly IHttpContextAccessor accessor;
public ConfigureConnection (IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public void Configure(ConnectionString config) {
config.Value = accessor.HttpContext.User ...
}
}
public class NestedService {
...
public NestedService(IOptions<ConnectionString> connection) {
ConnectionString = connection.Value.Value;
}
...
}
Further to #Tseng's extremely helpful answer, I found I could also adapt it to use delegates:
public delegate INestedService CreateNestedService(string connectionString);
services.AddTransient((provider) => new CreateNestedService(
(connectionString) => new NestedService(connectionString)
));
Implemented in RootService in the same way #Tseng suggested:
public class RootService : IRootService
{
public INestedService NestedService { get; set; }
public RootService(CreateNestedService createNestedService)
{
NestedService = createNestedService("ConnectionStringHere");
}
public void DoSomething()
{
// implement
}
}
I prefer this approach for cases where I need an instance of a factory in a class, as it means I can have a property of type CreateNestedService rather than Func<string, INestedService>.

Creating objects based on a string using Ninject

I need to create objects sharing common interface (IFoo) based on a string I get from the database. I have "A", I need to intantiate AFoo, I get "B", I need to produce BFoo, etc. The first thing I tought of was a factory. But the objects created (AFoo, BFoo) need to have their dependencies injected (and those dependencies need more dependencies and some even arguments). For all the injecting I use Ninject, which by itself seems to be a fancy factory. To create objects within my factory I inject a Ninject's kernel via constructor. Is that the desired way?
interface IBar { }
class Bar : IBar {
public Bar(string logFilePath) { }
}
interface IFoo { }
class AFoo : IFoo {
public AFoo(IBar bar) { }
}
class BFoo : IFoo { }
class FooFactory : IFooFactory {
private IKernel _ninjectKernel;
public FooFactory(IKernel ninjectKernel) {
_ninjectKernel = ninjectKernel;
}
IFoo GetFooByName(string name) {
switch (name) {
case "A": _ninjectKernel.Get<AFoo>();
}
throw new NotSupportedException("Blabla");
}
}
class FooManager : IFooManager {
private IFooFactory _fooFactory;
public FooManager(IFooFactory fooFactory) {
_fooFactory = fooFactory;
}
void DoNastyFooThings(string text) {
IFoo foo = _fooFactory.GetFooByName(text);
/* use foo... */
}
}
class Program {
public static void Main() {
IKernel kernel = new StandardKernel();
kernel.Bind<IBar>.To<Bar>();
kernel.Bind<IFooManager>.To<FooManager>();
kernel.Bind<IFooFactory>.To<FooFactory>();
IFooManager manager = kernel.Get<IFooManager>(new ConstructorArgument("ninjectKernel", kernel, true));
manager.DoNastyFooThings("A");
}
}
Ninject's IKernel's Get<T>() method has an overload which takes an name argument to get a named instance.
The usage would be:
public int Main()
{
IKernel kernel = new StandardKernel();
kernel.Bind<IFoo>().To<AFoo>().Named("AFoo");
kernel.Bind<IFoo>().To<BFoo>().Named("BFoo");
//returns an AFoo instance
var afoo = kernel.Get<IFoo>("AFoo");
//returns an BFoo instance
var bfoo = kernel.Get<IFoo>("BFoo");
}
Regarding your question about injecting Ninject's IKernel into the Factory's constructor, I don't think there should be any problems.
Your factory should look like this:
public interface IFooFactory
{
IFoo GetFooByName(string name);
}
public class FooFactory : IFooFactory
{
private readonly IKernel _kernel;
public FooFactory(IKernel kernel)
{
_kernel = kernel;
}
public IFoo GetFooByName(string name)
{
return _kernel.Get<IFoo>(name);
}
}
Also you could add a binding to IKernel like this:
kernel.Bind<IKernel>().ToConstant(kernel);

Abstract factories when using dependency injection frameworks

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);
};
});

Categories

Resources