is there a way i can merge 2 autoface container into 1?
I mean that all registrations from both containers will be included in the new one
Alternatively it could be upgrade one of them with the other
For example:
public IContainer Merge(IContainer container1, IContainer container2)
{
return ???;
}
I've tried iterating over "container.ComponentRegistry.Registrations" and by using containerBuilder registering components and upgrading the second container but for some reason there were some conflicts
Autofac.Core.DependencyResolutionException : An exception was thrown while executing a resolve operation. See the InnerException for details. ---> The provided instance has already been used in an activation request. Did you combine a provided instance with non-root/single-instance lifetime/sharing? (See inner exception for details.)
----> System.InvalidOperationException : The provided instance has already been used in an activation request. Did you combine a provided instance with non-root/single-instance lifetime/sharing?
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, ref Object instance)
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve(IComponentContext context, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve(IComponentContext context)
at Bootstrap.Bootstrapper.CreatePersistentTimerAsyncExecuter(IContainer container)
at Bootstrap.Bootstrapper.Monitor(IContainer container)
at Bootstrap.Bootstrapper.Boot(Assembly[] assemblies)
at Soluto.Telemetry.Processing.Core.IntegrationTests.TelemetryProcessingBootstrapperTests.Boot_With2TelemetryHandlersInAssembly_ResolvesSubscriberWithItsHandlers() in TelemetryProcessingBootstrapperTests.cs: line 88
--InvalidOperationException
at Autofac.Core.Activators.ProvidedInstance.ProvidedInstanceActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
at Autofac.Core.Resolving.InstanceLookup.Execute()
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
Any Ideas ?
You can use a custom IRegistrationSource. This interface contains a RegistrationsFor method that return a list of IComponentRegistration for a specific IService
public class CrossContainerRegistrationSource : IRegistrationSource
{
public CrossContainerRegistrationSource(IComponentContext componentContext)
{
this._componentContext = componentContext;
}
private readonly IComponentContext _componentContext;
public Boolean IsAdapterForIndividualComponents
{
get
{
return false;
}
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
return this._componentContext.ComponentRegistry.RegistrationsFor(service);
}
}
You can use it like this :
container2.ComponentRegistry.AddRegistrationSource(new CrossContainerRegistrationSource(container1));
But be careful with this solution it may introduce issue when you use complex scope scenario.
Yes it is possible.
var existingContainer = new ContainerBuilder();
// Add registrations to existing container.
var newContainerBuilder = new ContainerBuilder();
// Add registrations to new container.
newContainterBuilder.Update(existingContainer);
The update method essentially merges the contents of the existingContainer into the newContainerBuilder.
EDIT - If using an IContainer
If you have already built your ContainerBuilder into an IContainer the Update method of the ContainerBuilder is able to accept an IContainer as input. But in this case the already built container will now contain all the registrations and the new ContainerBuilder can go out of scope.
var builtContainer = existingContainer.Build();
var newContainerBuilder = new ContainerBuilder();
// Add registrations to new container.
newContainterBuilder.Update(builtContainer);
It should be noted that Update() is marked obsolete in newer versions of Autofac and should not be used. See https://github.com/autofac/Autofac/issues/811#issuecomment-270246744 for more clarification.
Some of the recommendations listed to get around this issue is:
Pass Around ContainerBuilder Instead of IContainer
Add Registrations to Child Scopes
Use Lambdas
Use Modules
Use Conditional Registrations (new in 4.4.0)
Basically.. don't end up with 2 containers if possible.
Thanks for all the answers guys,
eventually i did something more specific for my needs:
public void Merge(this IContainer container1, IContainer container2)
{
var newBuilder = new ContainerBuilder();
newBuilder.RegisterInstance(container2.Resolve<ISomeService1>()).AsImplementedInterfaces();
newBuilder.RegisterInstance(container2.Resolve<ISomeService2>()).AsImplementedInterfaces();
newBuilder.Update(container1);
return container1;
}
Related
How do I configure dependency injection in ASP.NET Core to return a certain instance depending on the type it's being injected into?
Let's say I have a simple interface,
public interface IHello
{
string SayHello();
}
And two different implementations:
public class Hello : IHello
{
public string SayHello() => "Hello...";
}
public class Hey : IHello
{
public string SayHello() => "HEY!";
}
And finally I have a few classes that all depend on an instance of IHello:
public class Class1
{
public Class1(IHello hello)
{
}
}
public class Class2
{
public Class2(IHello hello)
{
}
}
Now, in ConfigureServices I would do something like this:
services.AddSingleton<IHello, Hello>();
to configure any class depending on IHello to always get the same instance of Hello.
BUT: What I really want is for Class1 to always get the same singleton instance of Hey and all other classes should just get an instance of Hello. It could look like this in ConfigureServices (doesn't work, obviously):
services.AddSingleton<IHello, Hello>();
services.AddSingleton<IHello, Hey, Class1>(); // Doesn't work, but would be neat if it did...
Here's a simple approach. It lacks a certain elegance, but it will do what you need:
public static void Register(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton<Hello>();
serviceCollection.AddSingleton<Hey>();
serviceCollection.AddSingleton<ClassThatDependsOnIHello1>(serviceProvider =>
new ClassThatDependsOnIHello1(serviceProvider.GetService<Hello>()));
serviceCollection.AddSingleton<ClassThatDependsOnIHello2>(serviceProvider =>
new ClassThatDependsOnIHello2(serviceProvider.GetService<Hey>()));
}
There are two classes that depend on IHello. The registration for each of them includes a function. That function resolves either Hello or Hey from the service provider and passes it to the constructor of each respective class. That way you get control over which implementation gets passed to which class.
(It's beside the point that the service provider hasn't been built yet. The function you're providing will be executed later, and the service provider passed to it will be the one that has been built from the service collection.)
A downside to this is that now your DI registration explicitly calls your constructors. That can be a nuisance because if the constructors change (maybe you inject other dependencies) then you'll have to edit this code. That's not great, but it's not uncommon.
Plan B would be to do as Microsoft suggests and use another container.
Autofac
First, add the Autofac.Extensions.DependencyInjection NuGet package. This references Autofac and also provides the extensions needed to add an Autofac container to a service collection.
I've arranged this to focus on the way dependencies get registered with Autofac. It's similar to IServiceCollection and IServiceProvider. You create a ContainerBuilder, register dependencies, and then build a Container from it:
static void RegisterDependencies(this ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<Hello>().Named<IHello>("Hello");
containerBuilder.RegisterType<Hey>().Named<IHello>("Hey");
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.ResolveNamed<IHello>("Hello")
));
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.ResolveNamed<IHello>("Hey")
));
}
That's not really pretty either, but it sidesteps the problem of calling the constructors.
First it registers two implementations of IHello and gives them names.
Then it registers the two classes that depend on IHello. WithParameter(new ResolvedParameter()) uses two functions:
The first function determines whether a given parameter is the one we want to resolve. So in each case we're saying, "If the parameter to resolve is IHello, then resolve it using the next function."
It then resolves IHello by specifying which named registration to use.
I'm not excited by how complicated that is, but it does mean that if those classes have other dependencies injected, they'll be resolved normally. You can resolve ClassThatDependsOnIHello1 without actually calling its constructor.
You can also do it without the names:
static void RegisterDependencies(this ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<Hello>();
containerBuilder.RegisterType<Hey>();
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.Resolve<Hello>()
));
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(IHello),
(parameter, context) => context.Resolve<Hey>()
));
containerBuilder.RegisterType<SomethingElse>().As<ISomethingElse>();
}
We can clean that up some with an method that simplifies creating that ResolvedParameter because that's so hideous.
public static ResolvedParameter CreateResolvedParameter<TDependency, TImplementation>()
where TDependency : class
where TImplementation : TDependency
{
return new ResolvedParameter((parameter, context) => parameter.ParameterType == typeof(TDependency),
(parameter, context) => context.Resolve<TImplementation>());
}
Now the previous registration becomes:
containerBuilder.RegisterType<ClassThatDependsOnIHello1>().WithParameter(
CreateResolvedParameter<IHello, Hello>());
containerBuilder.RegisterType<ClassThatDependsOnIHello2>().WithParameter(
CreateResolvedParameter<IHello, Hey>());
Better!
That leaves the details of how you integrate it with your application, and that varies with your application. Here's Autofac's documentation which provides more detail.
For testing purposes you can do this:
public static IServiceProvider CreateServiceProvider()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterDependencies();
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
I like to write unit tests for this sort of thing. This method will create an IServiceProvider from the Autofac container, and then you can test resolving things from the container to make sure they get resolved as expected.
If you prefer another container, see if it has similar integrations to use it with Microsoft's container. You might find one you like better.
Windsor
Here's a similar example using Castle.Windsor.MsDependencyInjection.
public static class WindsorRegistrations
{
public static IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection)
{
var container = new WindsorContainer();
container.RegisterDependencies();
return WindsorRegistrationHelper.CreateServiceProvider(container, serviceCollection);
}
public static void RegisterDependencies(this IWindsorContainer container)
{
container.Register(
Component.For<Hello>(),
Component.For<Hey>(),
Component.For<ClassThatDependsOnIHello1>()
.DependsOn(Dependency.OnComponent<IHello, Hello>()),
Component.For<ClassThatDependsOnIHello2>()
.DependsOn(Dependency.OnComponent<IHello, Hey>())
);
}
}
There are two things I like about this:
It's so much easier to read! When resolving ClassThatDependsOnIHello2, fulfill the dependency on IHello with Hey. Simple.
This - WindsorRegistrationHelper.CreateServiceProvider(container, serviceCollection) - allows you to register dependencies with the IServiceCollection and include them in the service provider. So if you have existing code that registers lots of dependencies with IServiceCollection you can still use it. You can register other dependencies with Windsor. Then CreateServiceProvider mixes them all together. (Maybe Autofac has a way to do that too. I don't know.)
I am configuring AutoMapper to map domain objects from / to the view model ones in a Asp.Net MVC5 application with Autofac 4.3, Autofac.Owin 4, Autofac.Mvc5 4, AutoFac.Mvc5.Owin 4 and AutoMapper 5.2.
I did decide to create one AutoMapper profile per domain entity like the followin leaving only the constructor with no parameters because I want to set the profile's name.
Note: this code is in assembly A.
public partial class DoctorsMappingProfile : Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
// Code of mapping removed because it is not part of the problem
}
#endregion Constructors
}
To register AutoMapper and the profiles I followed this and this guides well explained by the user mpetito there and that it works as the user has checked here. My code in the Startup partial class is this:
Note1: this code is in assembly B which references assembly A.
Note2: I perfom assembly scanning of registered assemblies, then I pass as paramerter the array of scanned assemblies to the method RegisterAssemblyTypes of ContainerBuilder
public partial class Startup
{
#region Methods
public void ConfigureAutoFacContainer(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterFilterProvider();
builder.RegisterSource(new ViewRegistrationSource());
// TODO: Logger!
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
this.ConfigureAutoMapper(builder, assemblies);
// TODO: Modules!
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As<Profile>(); //.UsingConstructor(typeof(string));
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
#endregion Methods
}
When de application runs and try to resolve the profile the following exception happens:
Autofac.Core.DependencyResolutionException
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'AutoMapper.Configuration.MapperConfigurationExpression+NamedProfile' can be invoked with the available services and parameters: Cannot resolve parameter 'System.String profileName' of constructor 'Void .ctor(System.String, System.Action`1[AutoMapper.IProfileExpression])'.
the line of the error is the foreach loop when the context attempts to resolve the Profile:
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
I believe it its due to the Autofac default constructor location convention it is looking for the constructor with most parameters, which is in case of the AutoMapper.Profile class:
protected Profile(string profileName, Action<IProfileExpression> configurationAction)
{
}
To fix this I replaced the line that looks for profiles, the first line of code in in ConfigureAutoMapper, forcing it to use the constructor with no parameters:
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As<Profile>().UsingConstructor();
but still it does not work.
Solutions / workaround I have found:
If I replace the class Profile by my DoctorsMappingProfile in method ConfigureAutoMapper it works but doing this will invalidate the assembly scanning for profiles.
Finally I managed it to work by creating a base abstract class inheriting from AutoMapper.Profile and referencing it in my ConfigureAutoMapper method of the Startup class, this way I can perform assembly scanning for that class' descendants...
Note: this code is in Assembly C
public abstract class G2AutoMapperProfile : Profile
{
#region Constructors
protected G2AutoMapperProfile()
{
}
protected G2AutoMapperProfile(string profileName) : base(profileName)
{
}
#endregion Constructors
}
Note: And this code is in assembly A
public partial class DoctorsMappingProfile : G2AutoMapperProfile //Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
//removed because it is not part of the problem
}
#endregion Constructors
}
and finally, this is the code of ConfigureAutoMapper in assembly B, that works:
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(G2AutoMapperProfile)).As<G2AutoMapperProfile>();
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve<IEnumerable<G2AutoMapperProfile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
... but still I don't understand why the original code is not working for me.
First, there's no need for you to explicitly call the protected constructor of Profile in your DoctorsMappingProfile. The reason is that the profileName you pass is the one used by default by AutoMapper as we can see here.
Also, regarding the first way you try to register your profiles in the Autofac container:
builder
.RegisterAssemblyTypes(registeredAssemblies)
.AssignableTo(typeof(Profile))
.As<Profile>()
.UsingConstructor(typeof(string));
This means that you explicitly ask Autofac to create instance of your Profile classes by using the constructor that has exactly one parameter that is of type string. The problem with that is Autofac has no idea what string it has to use in the constructor.
It's also wrong since you created a parameter-less constructor which in turn calls the parameterized constructor.
I'm not sure what calling UsingConstructor with no parameters does, but in my opinion, you'd be better off leaving Autofac choose the best constructor for you, especially when the defaut parameter-less one is the one you want it to use.
My feeling is reinforced by looking at the solution/workaround you provided. What you effectively did is:
create a base class that mimics exactly what Profile has, that is, a default parameter-less constructor and a constructor that takes a string
register the profiles in the Autofac container by not using UsingConstructor
So I'm quite sure that by:
getting rid of your custom base class
having your profiles inherit from Profile again
registering your profiles without using UsingConstructor
you should be fine.
I am using Unity as my IoC framework and I am creating a type based on the value in the header of each request in a handler:
var container = new UnityContainer();
container.RegisterType<IFoo,Foo>(new InjectionConstructor(valuefromHeader));
GlobalConfiguration.Configuration.DependencyResolver =
new Unity.WebApi.UnityDependencyResolver(container);
The problem is that the handler's SendAsync means that the global container is getting overwritten by different requests and the controllers that use IFoo in their constructor are getting the wrong values.
1) Can I make the SendAsync sync?
2) If not, how do I create different instances for each request and have the IoC container resolve safely?
I have looked at the following articles without success:
http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver
http://www.strathweb.com/2012/11/asp-net-web-api-and-dependencies-in-request-scope/
http://benfoster.io/blog/per-request-dependencies-in-aspnet-web-api-using-structuremap
Thanks in advance.
I agree with #Steven's approach, but that doesn't answer your more general question of how to resolve per request.
I would recommend you change to using the UnityHierarchicalDependencyResolver and then anything you register with HierarchicalLifetimeManager will be resolved per request.
Change this...
GlobalConfiguration.Configuration.DependencyResolver =
new Unity.WebApi.UnityDependencyResolver(container);
to this...
GlobalConfiguration.Configuration.DependencyResolver =
new Unity.WebApi.UnityHierarchicalDependencyResolver(container);
The problem you are having is caused by you mixing runtime values with design time dependencies. In general, the services you resolve from the container should not depend on runtime values in their constructor. You shouldn't do this, because components tend to live much longer than runtime values and injecting runtime values into components, makes it much harder to diagnose and verify the container's configuration.
Instead, hide that value behind a service that can provide consumers with that instance when required. For instance:
public interface IHeaderValueProvider
{
HeaderValue GetCurrentValue();
}
You can create an implementation that can be easily registered and injected into any component that needs that value. Anytime after the construction phase, those components can call the GetCurrentValue() method on the injected IHeaderValueProvider dependency.
I managed to resolve per request by declaring my custom UnityResolver's class within the WebApiConfig class. The UnityResolver class uses the HttpConfiguration class assuming you're using an OWIN context.
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var _container = new UnityContainer();
DependencyConfiguration.ConfigureContainer(_container);
config.DependencyResolver = new UnityResolver(_container);
}
The ConfigureContainer class is simply a class where I declare my IOC dependencies as shown below:
private static void RegisterReleaseEnv(IUnityContainer container)
{
//Repository Registration
container
.RegisterType(typeof(IRepository<>), typeof(GenericRepository<>), new HierarchicalLifetimeManager());
}
It is very important that you use the HierarchicalLifetimeManager lifetime manager so that you get a new instance per request.
The UnityResolver class then looks like this:
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
I hope this helps.
For more information: http://www.asp.net/web-api/overview/advanced/dependency-injection
I use the following code in order to register log4net for all the classes that need it.
public class LogInjectionModule : Module
{
private readonly string _configPath;
public LogInjectionModule(string configPath)
{
_configPath = configPath;
}
protected override void AttachToComponentRegistration(IComponentRegistry registry,
IComponentRegistration registration)
{
XmlConfigurator.Configure(new FileInfo(_configPath));
registration.Preparing += OnComponentPreparing;
}
private static void OnComponentPreparing(object sender, PreparingEventArgs e)
{
var t = e.Component.Activator.LimitType;
e.Parameters = e.Parameters.Union(new[]
{
new ResolvedParameter((p, i) => p.ParameterType == typeof (ILog),
(p, i) => LogManager.GetLogger(t))
});
}
}
All the classes are registered using autofac's types scanning:
builder.RegisterAssemblyTypes(typeof (IResourceFinder).Assembly)
.AsImplementedInterfaces();
And it works fine!
One class needs to be registered explicitly tries to resolve ILog and fails
builder.Register(x => new ClassThatNeedsILog(x.Resolve<ILog>())).AsImplementedInterfaces();
Here is that class
public class ClassThatNeedsILog
{
public ClassThatNeedsILog(ILog log)
{
}
}
I am getting the following exception:
Autofac.Core.Registration.ComponentNotRegisteredException : The
requested service 'log4net.ILog' has not been registered. To avoid
this exception, either register a component to provide the service,
check for service registration using IsRegistered(), or use the
ResolveOptional() method to resolve an optional dependency.
Your LogInjectionModule never registers any ILog into the container only supplies paramters for the resolved instances on the preparing face, and it only works for instances created by Autofac.
So when you write builder.Register(x => new ClassThatNeedsILog(x.Resolve<ILog>())) you are creating the ClassThatNeedsILog manually. with new ClassThatNeedsILog(...)
Hence Autofac does not know about your instance creation (so your OnComponentPreparing won't run) and because you haven't really registered any ILog implementation you get the ComponentNotRegisteredException.
You have two options:
register an ILog in the container directly
let Autofac create your ClassThatNeedsILog type.
So you can just register an ILog in the container with:
builder.RegisterInstance(LogManager.GetLogger("Logger")).As<ILog>();
Then your code will work fine.
Or if you anyway creating the ClassThatNeedsILog by hand can just supply directly the ILog there:
builder.Register(x => new
ClassThatNeedsILog(LogManager.GetLogger(typeof(ClassThatNeedsILog))))
.AsImplementedInterfaces();
The other options is to let Autofac create the instances for you, so change your registration to:
builder.RegisterType<ClassThatNeedsILog>()
.AsImplementedInterfaces();
In this case Autofac will handle the instance creation for you and it will call the OnComponentPreparing method of your module.
If you want to supply additional constructor parameters you can use WithParameter and WithParameters methods:
builder.RegisterType<ClassThatNeedsILog>()
.AsImplementedInterfaces()
.WithParameters(new Parameter[] {
ResolvedParameter.ForNamed<IAnotherInterface>("NAME"),
ResolvedParameter.ForNamed<IYetAnotherInterface>("ANOTHERNAME")});
The builder needs to Build a container before it can Resolve.
Try something like this (untested)
builder
.RegisterAssemblyTypes(typeof (IResourceFinder).Assembly)
.AsImplementedInterfaces();
/* process LogInjectionModule */
IContainer container = builder.Build();
var updateBuilder = new ContainerBuilder();
updateBuilder
.Register(x => new ClassThatNeedsILog(x.Resolve<ILog>()))
.AsImplementedInterfaces();
updateBuilder.Update(container);
nemesv's answer resolved the issue for me.
Though, I had to spend some more time getting it to work after using the RegisterType approach, as I was missing the below:
config.Filters.AddRange(config.DependencyResolver.GetServices(typeof(IExceptionFilter)).Select(o => o as IExceptionFilter));
Just adding mentioning it here, if other's have forgotten to configure the filter in the first place.
In trying to configure ServiceStack.net to use Ninject as its IOC, I am getting errors referring to various bindings not being defined. Primarily for ICache Client.
What specific bindings need to be created to use Ninject properly?
Currently have specified:
Bind<ISessionFactory>().To<SessionFactory>();//Is this correct/needed?
Note
I have created an IContainerAdapter as per the ServiceStack documention to implement the use of Ninject.
(Found here:ServiceStack IOC Docs)
Note 2
My apphost configure method looks like this:
public override void Configure(Funq.Container container)
{
IKernel kernel = new StandardKernel(new BindingModule());
container.Adapter = new NinjectContainerAdapter(kernel);
}
Note 3
I have registered the ICacheClient as follows:
Bind().To();
And I am now getting an error pointing to IRequest
Error activating IRequestLogger\nNo matching bindings are available, and the type is not self-bindable
Container Adapter
public class NinjectContainerAdapter : IContainerAdapter
{
private readonly IKernel _kernel;
public NinjectContainerAdapter(IKernel kernel)
{
this._kernel = kernel;
}
public T TryResolve<T>()
{
return this._kernel.Get<T>();
}
public T Resolve<T>()
{
return this._kernel.Get<T>();
}
}
Have you injected your Container adapter with:
container.Adapter = new NinjectIocAdapter(kernel);
If so, try also make your AppHost class internal if you haven't done so. There should only be 1 instance of AppHost and some IOC's like to create their own instance, wiping out all the configuration from the first one.
The behavior you're getting sounds like Ninject is complaining about unresolved dependencies. Make sure you get Ninject to return null with Unresolved dependencies by using kernal.TryGet<T> in your Container Adapter, e.g:
public T TryResolve<T>()
{
return this._kernel.TryGet<T>();
}
You need to write your own IContainerAdapter and then set Container.Adapter in your AppHost