In StructureMap you could declare a Forward<,> statement, that would allow for registering a single concrete instance to be resolved by multiple interfaces from the StructureMap documentation:
var container = new Container(_ =>
{
// Let's make StatefulCache a SingletonThing in the container
_.ForConcreteType<StatefulCache>().Configure.Singleton();
_.Forward<StatefulCache, IReader>();
_.Forward<StatefulCache, IWriter>();
});
container.GetInstance<IReader>().ShouldBeOfType<StatefulCache>();
container.GetInstance<IWriter>().ShouldBeOfType<StatefulCache>();
I am looking at potentially migrating to Lamar, the replacement for StructureMap but I am not seeing anything matching this in the registration options.
Is this possible in Lamar?
According to StructureMap documentation the syntax has consistently been confusing to users and the suggested replacement is:
_.For<IReader>().Use(c => c.GetInstance<StatefulCache>());
So I would suggest using this lambda approach.
Related
I don't see how to register & resolve types with the same interface for use with a decorator. In order to get resolved with the decorator and the same instances of ILogger and IConfiguration, I am declaring them like so:
builder.RegisterType<FluentFtpFileHandler>().Named<IFileHandler>("fileHandler");
builder.RegisterType<LocalFileHandler>().Named<IFileHandler>("fileHandler");
builder.RegisterDecorator<IFileHandler>((c, inner) =>
new LogDecorator(inner.Logger, inner.Configuration, inner), fromKey: "fileHandler");
Within a factory class, how can I resolve e. g. an instance of FluentFtpFileHandler?
When you register multiple types that implement the same interface, last in wins.
builder.RegisterType<FluentFtpFileHandler>().As<IFileHandler>();
builder.RegisterType<LocalFileHandler>().As<IFileHandler>();
var container = builder.Build();
var handler = container.Resolve<IFileHandler>();
// handler is going to be LocalFileHandler
// because LAST IN WINS.
If you need to resolve different handlers in different situations, that's sort of a code smell because you can't actually treat all the handlers the same. There's an FAQ on that which explains, with examples, why that's not so great but also provides some ideas for workaround.
Back to the decorator situation, I'd recommend trying out the new decorator syntax since it's less confusing than the classic syntax.
builder.RegisterType<FluentFtpFileHandler>().Named<IFileHandler>("ftpHandler");
builder.RegisterType<LocalFileHandler>().Named<IFileHandler>("localHandler");
builder.RegisterDecorator<LogDecoerator, IFileHandler>();
var container = builder.Build();
var handler = container.ResolveNamed<IFileHandler>("ftpHandler");
// Handler should be a decorated instance of the FTP handler.
I'm running this through my "pretty sure this should work" mental compiler, so if the syntax isn't literally copy/paste there, I'm sorry about that.
I'm a relatively new user of both Autofac and ASP.NET Core. I've recently ported a small project from a 'classic' ASP.NET WebAPI project to ASP.NET Core. I am having trouble with Autofac, specifically in registration of generic types.
This project uses a Command pattern, each command handler is a closed generic like
public class UpdateCustomerCommandHandler: ICommandHandler<UpdateCustomerCommand>
These command handlers are injected into the controllers like:
readonly private ICommandHandler<UpdateCustomerCommand> _updateCustomerCommand;
public ValuesController(ICommandHandler<UpdateCustomerCommand> updateCustomerCommand)
{
_updateCustomerCommand = updateCustomerCommand;
}
Autofac is configured (partially) as:
var builder = new ContainerBuilder();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
//This doesn't seem to be working as expected.
builder.RegisterAssemblyTypes(assemblies)
.As(t => t.GetInterfaces()
.Where(a => a.IsClosedTypeOf(typeof(ICommandHandler<>)))
.Select(a => new KeyedService("commandHandler", a)));
The above does not seem to be registering the generic as expected. If I use the below method for registration, it works well.
builder.RegisterType<UpdateCustomerCommandHandler>().As<ICommandHandler<UpdateCustomerCommand>>();
When I say "It doesn't work", what I mean is that when attempting to instantiate the controller, I get "InvalidOperationException: Unable to resolve service for type 'BusinessLogic.ICommandHandler`1[BusinessLogic.UpdateCustomerCommand]' while attempting to activate 'AutoFac_Test.Controllers.ValuesController'."
This worked well in the Full WebAPI version of this project, but not after recreating it in ASP.NET Core. To be clear, this was working perfectly well before porting to ASP.NET Core.
Here is a link to the code that I've used to recreate this issue:
https://dl.dropboxusercontent.com/u/185950/AutoFac_Test.zip
**** EDIT AFTER SOLUTION DISCOVERED ****
There was nothing in fact wrong with my Autofac configuration and certainly not Autofac itself. What had happened was that I had renamed the output of my dependent assemblies in an effort to make the assembly scanning stuff (replacing of AppDomain.CurrentDomain.GetAssemblies() more elegant, however I never modified the dependencies of the API project to reference the new assemblies. So Autofac was scanning the correctly loaded assemblies which happened to be the older versions, which did not contain the interfaces and implementations I expected...
Autofac has built-in support to register closed types of open-generic.
builder
.RegisterAssemblyTypes(ThisAssembly)
.AsClosedTypesOf(typeof(ICommandHandler<>));
This will scan your assembly, find types that close the open generic ICommandHandler<> interface, and register each of them against the closed generic interface they implement - in your case, ICommandHandler<UpdateCustomerCommand>.
What doesn't work in your example is that you associate a key to your services. Autofac doesn't look for the keyed version of your ICommandHandler<UpdateCustomerCommand> when trying to instantiate the ValuesController, which is why you get the exception.
Edit after QuietSeditionist's comment:
I'll try to elaborate a bit on the keyed vs. default services. The way you registered your handlers is by associating the commandHandler key to them.
This means that once the container is built, here's the only way you can resolve such a handler:
// container will look for a registration for ICommandHandler<UpdateCustomerCommand> associated with the "commandHandler" key
container.ResolveKeyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler");
When instantiating ValuesController, Autofac doesn't look for a keyed registration of ICommandHandler<UpdateCustomerCommand>, because it wasn't asked to.
The equivalent code it's executing is - and you can try to run that code yourself to get the exception:
// BOOM!
container.Resolve<ICommandHandler<UpdateCustomerCommand>>();
The reason your second registration works is because you didn't key the service:
// No key
builder
.RegisterType<UpdateCustomerCommandHandler>()
.As<ICommandHandler<UpdateCustomerCommand>>();
// commandHandler key
builder
.RegisterType<UpdateCustomerCommandHandler>()
.Keyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler");
But since you don't want to register all your handlers one by one, here's how to register them without keying them:
builder
.RegisterAssemblyTypes(ThisAssembly)
.AsClosedTypesOf(typeof(ICommandHandler<>));
/Edit
I can see two scenarios where keying services can be useful:
You have several types implementing the same interface and you want to inject different implementations in different services. Let's say, you register both SqlConnection and DB2Connection as IDbConnection. You then have 2 services, one which is supposed to target SQL Server, the other one DB2. If they both depend on IDbConnection, you want to make sure you inject the correct one in each service.
If you use decorators, the way registrations work is you define the services to which the decorators will apply by a key - the first example is self-explanatory
Because Google brings you to this page even when you're trying to manually register types, I thought that even though this doesn't answer the asked question, it would be useful for future visitors. So, if you want to manually register a generic type, you would use this format:
service.AddTransient(typeof(IThing<>), typeof(GenericThing<>));
or if there's no interface, then just:
service.AddTransient(typeof(GenericThing<>));
and for completeness, if you have a generic with multiple types:
services.AddTransient(typeof(GenericThing<,>));
My question is really a repeat of an old question posted here:
Ninject 2.2 multiple bindings
It seems someone was going to deal with this back in 2011. Does anyone know if there is some way to turn off such warnings in Ninject? Or some other workaround?
EDIT
In response to #BatteryBackupUnit, here is my exact problem:
I have multiple libraries... and in my core library, I do something like this:
Find all assemblies referenced by the host application (including the host)
Find all types inheriting from IDependency from all those assemblies.
Automatically register all of those as transient
Then from another library (which may or may not be referenced by the host app), I have this:
Kernel.Bind<IDbContextFactory>().To<DbContextFactory>().InSingletonScope();
Here IDbContextFactory is also an IDependency, so it got loaded already by the core library and now I register it here but with a different scope (singleton).
From experience (and having tested it earlier) I know this is no problem in Autofac, but Ninject gives me that error message about having already registered it.
Ideally it would be better to just override any previous registrations... "cascade style" (for lack of a better phrase)..
Ninject does now support overriding open generic bindings with more specific ones.
For Example:
public interface IFoo<T> { }
public class Foo<T> : IFoo<T> { }
public class StringFoo : IFoo<string> {}
used like:
var kernel = new StandardKernel();
kernel.Bind(typeof(IFoo<>)).To(typeof(Foo<>));
kernel.Bind<IFoo<string>>().To<StringFoo>();
var intFooInstance = kernel.Get<IFoo<int>>();
var stringFooinstance = kernel.Get<IFoo<string>>();
Works.
However, if you're not talking about open generic bindings, ninject 3 still handles multi bindings the same as ninject 2.2.
In most scenarios you can work around this by using contextual bindings. Okay i would not exactly call it a workaround, i would call it good design.
In general this is described here: https://github.com/ninject/ninject/wiki/Contextual-Binding
A simple way would be to specify the binding using a name. This requires one binding for the specified one and allows only one, too.
See: https://github.com/ninject/ninject/wiki/Contextual-Binding#simple-constrained-resolution-named-bindings
It is also possible to define a "default" binding like .Bind<IFoo>().To<Foo>(); and special case bindings with the .When(...) syntax, like:
.Bind<IFoo>().To<SpecialFoo>().When(ctx => ...)
See https://github.com/ninject/ninject/wiki/Contextual-Binding#specifying-constraints-on-the-type-binding-using-arbitrary-elements-of-the-resolution-request-context
If you show us your concrete problem we might be able to provide a more concrete solution.
container.Register <IRep<T>>(c => new Rep<T>())); /// Exception :)
container.RegisterAllTypesOf<IRep> (....)
Funq doesn't support this out of the box, see this comment from the owner - How do I register a generic service. Your best bet is to make use of your ability to provide your own container. I know that Autofac supports this - Autofac Open Generics
I have this object "mySessionObject" of type "SessionObject". It implements the interfaces IMessageHandler<MessageA> and IMessageHandler<MessageB>. I should only have one of these objects, and it should live thru the entire HttpSession.
How do I register it with structuremap so that I at any time in the lifetime of the HttpSession can get it by calling ObjectFactory.GetInstance<IMessageHandler<MessageA>>(), or ObjectFactory.GetInstance<IMessageHandler<MessageB>>() ?
Inside of your normal StructureMap configuration, I would add this code:
ObjectFactory.Initialize(x =>
{
x.ForRequestedType<IMessageHandler<MessageA>>().
TheDefaultIsConcreteType<MyImplementingClass>().
CacheBy(InstanceScope.HttpSession);
x.ForRequestedType<IMessageHandler<MessageB>>().
TheDefaultIsConcreteType<MyImplementingClass>>().
CacheBy(InstanceScope.HttpSession);});
}
Note that you will need the 2.5.3 StructureMap release as detailed in this SO thread: StructureMap CacheBy InstanceScope.HttpSession not working
I'm away from a compiler at the moment, but I believe that CacheBy is smart enough to share objects between implementing classes. If not, you can construct a MyImplementingClass another way, and then use TheDefaultIs() rather than TheDefaultIsConcreteType().