Why can't I bind System.IO.Abstractions with Ninject? - c#

I am just learning to use dependency injection with Ninject, and am using System.IO.Abstractions to abstract the filesystem. I am trying to use Ninject to bind DirectoryInfoBase to DirectoryInfo as so:
IKernel ninject = new StandardKernel();
ninject.Bind<DirectoryInfoBase>().To<DirectoryInfo>();
But am getting the error
Error 1 The type 'System.IO.DirectoryInfo' cannot be used as type parameter 'TImplementation' in the generic type or method 'Ninject.Syntax.IBindingToSyntax.To()'. There is no implicit reference conversion from 'System.IO.DirectoryInfo' to 'System.IO.Abstractions.DirectoryInfoBase'. C:\Users\Trevor\Dropbox\Code\PhotoOrganiser\PhotoOrganiser\Program.cs 13 13 PhotoOrganiserApp
What am I missing here? I thought the goal of libraries such as this was to be able to perform these sorts of tasks?

System.IO.Abstractions is using the Adapter Pattern. It is a trick used for certain types that don't have any abstraction (abstract class or interface) in order to use them with DI. Since there is no way to add an abstraction to an existing type in .NET, a wrapper (adapter) is created which has an abstraction (in this case, an abstract class) in order to use to loosely couple the implementation.
The problem here is that you are not using the wrapper, you are using the implementation directly.
IKernel ninject = new StandardKernel();
ninject.Bind<DirectoryInfoBase>().To<DirectoryInfoWrapper>()
.WithConstructorArgument("instance", new DirectoryInfo(#"C:\Somewhere\"));
However, there is another gotcha here - DirectoryInfo requires a directory path as a constructor argument. So this means it typically makes more sense to use an Abstract Factory so it can be created at runtime when the directory path is known. In this case, it makes more sense to inject the factory into your service and then call the method to create the instance at runtime. The author of System.IO.Abstractions made the factory internal, but you can build one just the same.
[Serializable]
public class DirectoryInfoFactory : IDirectoryInfoFactory
{
public DirectoryInfoBase FromDirectoryName(string directoryName)
{
var realDirectoryInfo = new DirectoryInfo(directoryName);
return new DirectoryInfoWrapper(realDirectoryInfo);
}
}
public class SomeService : ISomeService
{
private readonly IDirectoryInfoFactory directoryInfoFactory;
public SomeService(IDirectoryInfoFactory directoryInfoFactory)
{
if (directoryInfoFactory == null)
throw new ArgumentNullException("directoryInfoFactory");
this.directoryInfoFactory = directoryInfoFactory;
}
public void DoSomething()
{
// The directory can be determined at runtime.
// It could, for example, be provided by another service.
string directory = #"C:\SomeWhere\";
// Create an instance of the DirectoryInfoWrapper concrete type.
DirectoryInfoBase directoryInfo = this.directoryInfoFactory.FromDirectoryName(directory);
// Do something with the directory (it has the exact same interface as
// System.IO.DirectoryInfo).
var files = directoryInfo.GetFiles();
}
}
And then configure the container to inject a factory that can create multiple runtime instances rather than a single instance.
IKernel ninject = new StandardKernel();
ninject.Bind<IDirectoryInfoFactory>().To<DirectoryInfoFactory>();
But there is another trick the author of System.IO.Abstractions used to take it a step further. He made an Aggregate Service that can be injected and provide many of the services that types in the System.IO namespace provide in a loosely-coupled way.
So, rather than making your own factory, you could instead inject the existing IFileSystem service in order to gain access to virtually any of the services the System.IO namespace provides.
public class SomeService : ISomeService
{
private readonly IFileSystem fileSystem;
public SomeService(IFileSystem fileSystem)
{
if (fileSystem == null)
throw new ArgumentNullException("fileSystem");
this.fileSystem = fileSystem;
}
public void DoSomething()
{
// The directory can be determined at runtime.
// It could, for example, be provided by another service.
string directory = #"C:\SomeWhere\";
// Create an instance of the DirectoryInfoWrapper concrete type.
DirectoryInfoBase directoryInfo = this.fileSystem.DirectoryInfo.FromDirectoryName(directory);
// Do something with the directory (it has the exact same interface as
// System.IO.DirectoryInfo).
var files = directoryInfo.GetFiles();
}
}
You would then configure the container just to inject IFileSystem to gain all of the functionality of System.IO.
IKernel ninject = new StandardKernel();
ninject.Bind<IFileSystem>().To<FileSystem>();

You can't use that particular binding because DirectoryInfo doesn't inherit from or implement DirectoryInfoBase.
You might have been misled by the fact you can do cast a DirectoryInfo to a DirectoryInfoBase using
DirectoryInfo dirInfo;
DirectoryInfoBase dirInfoBase = (DirectoryInfoBase)dirInfo;
but that is only possible because of an implicit cast operator in DirectoryInfoBase:
public static implicit operator DirectoryInfoBase(DirectoryInfo directoryInfo)
{
if (directoryInfo == null)
return null;
return new DirectoryInfoWrapper(directoryInfo);
}
I'm not familiar with System.IO.Abstractions but why don't you just inject the IFileSystem, like in the example with
ninject.Bind<IFileSystem>().To<FileSystem>();
If you have a IFileSystem you can do
fileSystem.DirectoryInfo.FromDirectoryName(directoryName)
to get a DirectoryInfoBase object.

Related

Dependency Injection for factory with parameters resolved at creation time

Here's what I want to be able to do in my application:
public void BusinessLogic (IFactory workerFactory)
{
string specificObjectType = ... // not known in advance
IWorkerObject workerObject = workerFactory.CreateByType(specificObjectType);
workerObject.DoActualWork();
}
In other words, I want an actual Factory that generates various kinds of IWorkerObject implementations on demand, and I want that Factory to be injectable. And ideally that Factory itself would be able to get those implementation object from the service container too:
public class WorkerFactory
{
public WorkerFactory (IServiceContainer ...)
{ ... }
public IWorker CreateByType (string type)
{
return ...; // a thing that can be provided by the service container
}
}
The reason is that I want to be able to create (for example) a SteelWorker or a CopperWorker or an AluminumWorker depending on what type of metal is represented by that specificObjectType value. This seems like a normal Factory pattern to me, but I don't know how to make a class injectable and give it parameters that aren't resolved until creation time.
If this can be done with Unity, great. If I need to work around it or use another DI framework, that is okay too.
You could inject an IServiceScopeFactory into the IFactory
using (var scope = _serviceScopeFactory.CreateScope())
{
if(criteriaA)
{
return scope.ServiceProvider.GetRequiredService<WorkerA>();
}
}

Create Instance of a class from interface which it implements

Hi I am trying to build a generic UoWFactory which creates a UnitOfWork(there will be one default unitofwork and multiple custom implementaitons as well). So far I was able to create factory method which creates default UoW and returns it. I have modify the following method to return specified UoW depending on the parameter passed.
Current implementation
private BaseResult<IUnitOfWork> GetUnitOfWorkByCompiledModel<IUnitOfWork>(DbCompiledModel compiledModel)
{
return new BaseResult<IUnitOfWork>
{
Payload = new DbUnitOfWork(_context, _dbRepository, _mapper, _entityMapper)
};
}
I wish to have something like this
private BaseResult<TUoW> GetUnitOfWorkByCompiledModel<IUnitOfWork>(DbCompiledModel compiledModel) where TUoW :Class
{
return new BaseResult<TUoW>
{
//Create instance of type TUoW where TUoW can be IUnitOfWork, ICustomUnitOfWork etc
//DbUnitOfWork implements IUnitOfWork and CustomUnitOfWork implements ICustomUnitOfWork
//All the TUoW will have constructors with identical parmeters
};
}
Create an instance of class is straight forward
Activator.CreateInstance (Type type, object[] args);
But if I pass Interface type as a parameter how to create instance of DbUnitOfWork or CustomUnitOfWork.
eg:-
GetUnitOfWorkByCompiledModel<IUnitOfWork>(compiledModel);
GetUnitOfWorkByCompiledModel<ICustomUnitOfWork>(compiledModel);
Parameterless constructors
What you want is possible, except for one thing: you can't use non-default constructors with generic type arguments. You can't avoid that.
Part of the issue here is that you can't enforce specific constructor method signatures from an interface, so there is no way to guarantee that all implementation of IUnitOfWork are going to have the same constructor.
The simplest solution here is to step away from using constructors and instead use object initialization:
public interface IUnitOfWork
{
Foo Foo { get; set; }
}
private BaseResult<TUnitOfWork> GetUnitOfWorkByCompiledModel<TUnitOfWork>(DbCompiledModel compiledModel) where TUnitOfWork : IUnitOfWork, new()
{
return new BaseResult<TUnitOfWork>
{
Payload = new TUnitOfWork()
{
Foo = myFoo
};
};
}
I think this suits your expectations while being a minimal change.
Resolving interfaces
But if I pass Interface type as a parameter how to create instance of DbUnitOfWork or CustomUnitOfWork. eg
GetUnitOfWorkByCompiledModel<IUnitOfWork>(compiledModel);
GetUnitOfWorkByCompiledModel<ICustomUnitOfWork>(compiledModel);
If you intend to use interface types without concrete types, then the above answer is incomplete.
Regardless of the generic type issue, if you want to resolve an interface into a concrete type, you need to register which concrete type you want to use.
This is most commonly done via a Dependency Injection framework. These framework ask you to register all necessary types, e.g. a .NET Core example:
services.AddTransient<IUnitOfWork, MyUnitOfWork>();
services.AddTransient<ICustomUnitOfWork, MyCustomUnitOfWork>();
And the framework will then use this registration to automatically fill in constructor parameters for you:
public class Example
{
public Example(ICustomUnitOfWork uow)
{
}
}
The good practice approach here requires you to thread this dependency injection through your entire framework so you never need to call any constructor explicitly (and instead have the DI framework do it for you).
It is possible to use a service locator, which is essentially a DI framework that you call at-will. A small example of usage would be:
private BaseResult<TUnitOfWork> GetUnitOfWorkByCompiledModel<TUnitOfWork>(DbCompiledModel compiledModel) where TUnitOfWork : IUnitOfWork, new()
{
var uow = myServiceLocator.Get<TUnitOfWork>();
uow.Foo = myFoo;
return new BaseResult<TUnitOfWork>
{
Payload = uow;
};
}
This creates an instance of whichever concrete type was registered to the interface you're using as the generic parameter.
However, service locators are generally considered to be an anti-pattern, and I would strongly suggest that you avoid favor a cleaner IoC approach than this.
I can't elaborate fully on dependency injection in scope of a single StackOverflow answer. I suggest you look up dependency injection as it does exactly what you're expecting (getting a concrete type by referencing an interface)
This will be work if DbUnitOfWork Class has right name of values
What you want to change
Payload = new DbUnitOfWork(_context, _dbRepository, _mapper, _entityMapper);
Change as
Payload = new DbUnitOfWork() {
context = _context,
dbRepoitory = _dbRepository,
mapper = _mapper,
entityMapper = _entityMapper
};
hope this work.

Use Autofac for non-registered type initialization

I have a library that builds instances of types (all public and non-abstract) it discovers dynamically at runtime (using reflection).
To build those instances I want to use Autofac (though I'm willing to use other frameworks) so that the dependencies are automatically incorporated.
The problem is that Autofac is not creating the instance. If I use scope.Resolve() it throws an exception saying the type wasn't registered (which it can't be since it is discovered dynamically at runtime). If I try to use scope.ResolveOptional() it just returns null.
I've used it with types that have just a default public constructor and types that have dependencies and both fail.
EDIT: Added code. The types returned in the types array are all public types with a default parameterless constructor.
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(ISomeInterface).IsAssignableFrom(p)
&& !p.IsAbstract
&& p.IsPublic).ToArray();
var instance = (ISomeInterface)_dependencyInjectionScope.Resolve(type);
EDIT 2: Regarding some comments, yes I know that these types are not registered beforehand but that happens because the container is already fully built by the time this code is called. I'm looking if there is a way around it (after all I'm providing Autofac with a type that is both concrete and constructable)
Are you eventually looking for Registration Sources?
If so, please see the AnyConcreteTypeNotAlreadyRegisteredSource:
var builder = new ContainerBuilder();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
though I'm willing to use other frameworks
You can use the Unity container. It allows you to build objects of any class (not interfaces) without explicitly registering the classes with the container. Of course the classes have to be public, non-abstract, have a public constructor, and interface-based dependencies should be registered with the container.
Here is a sample code:
public interface IService
{
}
public class Service : IService
{
}
public class MyClass
{
private readonly IService m_Service;
public MyClass(IService service)
{
m_Service = service;
}
}
class Program
{
static void Main(string[] args)
{
UnityContainer container = new UnityContainer();
container.RegisterType<IService, Service>(); //We need to register interface-based dependency
var my_class = container.Resolve<MyClass>(); //We can resolve class-based types without registering them explicitly
}
}

Unity parameter constructor exception

Within the bootstrapper class of my WebApi I'm trying to register a new instance of a class called 'Facade' based on its interface type.
Within this type being regitered it requires a new instance of 'CRUDOperator' which also has a new instance of 'Adaptor' in its constructor. Is what I'm trying to do possible? I am currently just recieving an exception that the overload params are incorrect.
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
*****ERROR*****
container.RegisterType<IFacade,Facade>(new CRUDOperatorSelector(new Adapter()));
return container;
}
}
Unity is capable of resolving concrete types without registering them, so if in Your case the types CRUDOperatorSelector and Adapter are concrete types (and I'm assuming they are) you just have to register the type Facade as implementation of IFacade and resolve it. Unity will then create an instance of each dependency and pass it to the constructor of Facade.
If some of those types implement an abstraction (an interface or an abstract class) register them also.

How to use a Provider in Ninject

I have the following code
public class Something {
[Inject]
public Configuration config {get;set;} //singleton
[Inject]
public Provider<WindowHandler> windowsProvider { get; set; } //NOT singleton
public void Search(string text) {
WindowHandler handler = windowsProvider.Create(xxxxxx);
//use the new handler that was created
}
}
but it seems the Provider takes an IContext where I put xxxxxx. Shouldn't the IContext from when I bootstrapped and created Something.cs from the kernel be used. Where is the no parameter Create method on the Provider??? (I am coming from Guice land point of view where it would be coded like above).
so the question is How do I do this correctly?
thanks,
Dean
It seems you are trying to use a provider as a factory in your code.
A provider in Ninject terms is a factory that is given to Ninject to create specially created objects. Therefore it gets the resolving context which can be used to create different instances depending where the instance in injected into.
public class FooProvider : Provider<IFoo>
{
public override IFoo CreateInstance(IContext ctx)
{
// add here your special IFoo creation code
return new Foo();
}
}
kernel.Bind<IFoo>().ToProvider<FooProvider>();
What you want is a factory in your coder that creates an instance of WindowHandler. Therefore create an interface to create the instance like this:
public interface IWindowHandlerFactory
{
WindowHandler Create();
}
Bind<IWindowHandlerFactory>().ToFactory();
Alternatively you can inject Func<WindowHandler> without adding a configuration. But this is less meaningful in my opinion.
NOTE: All this requires Ninject.Extensions.Factory available as prerelease 3.0.0-rc2 from Nuget.
See also: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/
Well, my final solution was to cheat in ninject 2.0 with the following code...
var windowFactory = kernel.Get<IEWindowFactory>();
var tabFactory = kernel.Get<IETabFactory>();
windowFactory.Kernel = kernel;
tabFactory.Kernel = kernel;
and in the bindings list I have
Bind<IEWindowFactory>().ToSelf().InSingletonScope();
Bind<IETabFactory>().ToSelf().InSingletonScope();
and after that I just start my app
var main = kernel.Get<MainForm>();
main.Start();
and of course the factories are injected where I need them in the heirarchy of that MainForm.
so I manually put the kernel when starting up and then when I bootstrap my app, naturally these factories are fields in classes with [Ninject] annotation and so they can create objects. not the cleanest until we get 3.0, but it works(and I hate the extra factory classes I have to write code for but oh well).

Categories

Resources