In Ninject I can get object needed for interface by using class WebContainerManager
Ninject definition:
var logManager = new LogManagerAdapter();
container.Bind<ILogManager>().ToConstant(logManager);
Ninject usage:
var log = WebContainerManager.Get<ILogManager>().GetLog(typeof(WebApiApplication));
My question is how to do the same in Autofac, to get needed class for interface?
UPDATE 1: Im using WebAPi 2, not MVC.
If you need access to Autofac container from the class that was resolved by Autofac itself, then you can specify dependency on IComponentContext that is automatically provided by Autofac.
Example:
public void SomeComponent(IComponentContext context)
{
this.context = context;
}
...
// somewhere inside SomeComponent
context.Resolve<ILogManager>();
If your code is running inside ASP.Net environment, then you most probably set its DependencyResolver, thus you can always access it like:
DependencyResolver.Current.GetService<ILogManager>();
but as it is already mentioned in other comments, Service Locator is an anti-pattern that should be avoided.
In order to integrate autofac container with standard MVC dependency resolution mechanism you need to:
install Autofac.Mvc5 nuget package
set DependencyResolver with the following code
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
And in case you don't mind having explicit dependency on Autofac in your application code you can access global Autofac resolver reference the same way you use Ninject WebContainerManager:
var log = AutofacDependencyResolver.Current.Resolve<ILogManager>().GetLog(typeof(WebApiApplication));
You can create your builder.
var builder = new ContainerBuilder();
// Usually you're only interested in exposing the type
// via its interface:
builder.RegisterType<SomeType>().As<IService>();
// However, if you want BOTH services (not as common)
// you can say so:
builder.RegisterType<SomeType>().AsSelf().As<IService>();
Then you will be able to build your IoC:
IContainer Container = builder.Build();
And a simple example of How to get resource from container:
// Create the scope, resolve your IService,
// use it, then dispose of the scope.
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve<IService>();
writer.DoSomething();
}
Related
I have a .net core 2.1 console app. I'm building the container as below:
public IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
// Register services here.
// Unity container interface:
var containerFactory = new ServiceProviderFactory(null);
IUnityContainer container = containerFactory.CreateBuilder(services);
IServiceProvider serviceProvider = containerFactory.CreateServiceProvider(container);
return serviceProvider;
}
I need to provide constructor arguments to some of the services registered in the container. However, I do not want to use something like options pattern. Instead, I would like to access the Unity functionality with something like below:
var container = (UnityContainer)serviceProvider;
var foo = container.Resolve<IFoo>(new ParameterOverrides<Foo> { "name": "myFoo" });
The above approach is not working and throw the error:
Unable to cast object of type 'Unity.Microsoft.DependencyInjection.ServiceProvider' to type 'Unity.UnityContainer'.
Is there a way to do this or am I restricted to IServiceProvider interface even though I'm using Unity implementation?
EDIT:
So, I can't find a way to switch from IServiceProvider to IUnityContainer with something like a cast. So, I changed the above code a bit to return Unity container instead:
public IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
// Register services here.
// Unity container interface:
var containerFactory = new ServiceProviderFactory(null);
IUnityContainer container = containerFactory.CreateBuilder(services);
return container;
}
Now, I can use the usual Unity DI in the .Net Core App.
You should use NugetPackage which integrates Unity with ServiceProvider provided by .NET Core.
https://github.com/unitycontainer/microsoft-dependency-injection
I'm using ASP.NET Core and Autofac. Almost everything is registered as per lifetime scope ("per request"). So my database context DbContext is the same instance throughout a request.
However I have a singleton which also depends on DbContext. To avoid a captive dependency, it is injected as Func<Owned<DbContext>>, which means a new DbContext instance each time.
The problem is I need the same instance, as everywhere else during the request, not a new one.
I want to avoid a captive dependency bug, but I also want the same instance. Is that possible via tagging or a custom registration?
From the comments the least "architectural" painful approach may be by creating your own Scoped<T> class which will resolve the DbContext from current HttpContext
// Use an interface, so we don't have infrastructure dependencies in our domain
public interface IScoped<T> where T : class
{
T Instance { get; }
}
// Register as singleton too.
public sealed class Scoped<T> : IScoped<T> where T : class
{
private readonly IHttpContextAccessor contextAccessor;
private HttpContext HttpContext { get; } => contextAccessor.HttpContext;
public T Instance { get; } => HttpContext.RequestServices.GetService<T>();
public Scoped(IHttpContextAccessor contextAccessor)
{
this.contextAccessor = contextAccessor ?? throw new ArgumentNullException(nameof(contextAccessor));
}
}
Register it as
// Microsoft.Extensions.DependencyInjection
services.AddSingleton(typeof(IScoped<>), typeof(Scoped<>);
// Autofac
containerBuilder.RegisterType(typeof(Scoped<>))
.As(typeof(IScoped<>));
Then inject this into your validator service.
public class CustomerValidator: AbstractValidator<Customer>
{
private readonly IScoped<AppDbContext> scopedContext;
protected AppDbContext DbContext { get } => scopedContext.Instance;
public CustomValidator(IScoped<AppDbContext> scopedContext)
{
this.scopedContext = scopedContext ?? throw new ArgumentNullException(nameof(scopedContext));
// Access DbContext via this.DbContext
}
}
This way you can inject any scoped service w/o further registrations.
Additional notes
Autofac is considered a "conformer" (see docs) DI and integrates well with ASP.NET Core and Microsoft.Extensions.DependencyInjection.
From the documentation
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add services to the collection.
services.AddMvc();
// Create the container builder.
var builder = new ContainerBuilder();
// Register dependencies, populate the services from
// the collection, and build the container. If you want
// to dispose of the container at the end of the app,
// be sure to keep a reference to it as a property or field.
builder.RegisterType<MyType>().As<IMyType>();
builder.Populate(services);
this.ApplicationContainer = builder.Build();
// Create the IServiceProvider based on the container.
return new AutofacServiceProvider(this.ApplicationContainer);
}
There a few subtle differences to the default usage of Startup class and Microsoft.Extensions.DependencyInjection container.
ConfigureServices isn't void anymore, it returns IServiceProvider. This will tell ASP.NET Core to use the returned provider instead of DefaultServiceProvider from Microsoft.Extensions.DependencyInjection.
We return the Autofac container adapter: new AutofacServiceProvider(this.ApplicationContainer) which is the root container.
This is important to make ASP.NET Core use the container everywhere in ASP.NET Core, even inside middlewares which resolve per request dependencies via HttpContext.RequestedServices.
For that reasons you can't use .InstancePerRequest() lifetime in Autofac, because Autofac isn't in control of creating scopes and only ASP.NET Core can do it. So there is no easy way to make ASP.NET Core use Autofac's own Request lifetime.
Instead ASP.NET Core will create a new scope (using IServiceScopeFactory.CreateScope()) and use a scoped container of Autofac to resolve per-request dependencies.
I want to integrate Autofac to my API. Solution is split on several projects so that everything stays decoupled. I have set up my configure services like this:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
...
...
// Autofac
var builder = new ContainerBuilder();
builder.RegisterType<RouteRepository>().As<IRouteRepository>();
builder.Populate(services);
ApplicationContainer = builder.Build();
return new AutofacServiceProvider(ApplicationContainer);
}
However now with this code integrated, my API won't start anymore. If I start it in debug mode, I get no errors, but I don't get response either.
API landing route is pretty straightforward:
public IActionResult GetIndex()
{
return Ok("You are seeing this because controller is working!");
}
Also, what might be connected to the problem is that RouteRepository takes one variable as an argument in the constructor and I don't know where can I define what will be passed through? There is no config file by default.
If you're saying that you have one dependency for your RouteRepository, then you have to notify Autofac container how to resolve that:
// singletone
builder.RegisterInstance(new TaskRepository())
.As<ITaskRepository>();
// or instance based creation
builder.Register(c => new LogManager(DateTime.Now))
.As<ILogger>();
Or Autofac couldn't resolve your type.
A Mef CompositionContainer is unable to resolve Autofac dependencies when used according to documentation at http://docs.autofac.org/en/latest/integration/mef.html.
I have a large code-base that has extensive use of a ServiceLocator and singletons... The service-locator does all object-creation, composition etc by using a cached System.ComponentModel.Composition.Hosting.CompositionContainer. (Also, note that we currently use/need metadata support) I am attempting to switch from this to a more modern architecture. For this to work, the existing Mef-based (‘CompositionContainer’-based) service-locator will have to cooperate with the Autofac IoC container.
The following function
Creates a Mef CompositionContainer
Demonstrates that MEF is able to resolve a simple export
Configures Autofac to register with MEF and export the AutofacExport to MEF by using the .Exported extension method.
Demonstrates that Autofac can resolve a mef-component with a dependency definend in Autofac
Demonstrates that Mef is unable to resolve the exported component component with the Autofac dependency.
The exception thrown is: ImportCardinalityMismatchException("No exports were found that match the constraint: ContractName MefExportWithDependency RequiredTypeIdentity MefExportWithDependency" is thrown.
public void MefResolve_ObjectWithDependency_CanResolveWhenAutofacRegistersDependeyncy2()
{
//1. Initialize Mef
var composablePartCatalogs = new List<ComposablePartCatalog>
{
new AssemblyCatalog(Assembly.GetExecutingAssembly())
//A lot more here..
};
var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);
var container = new CompositionContainer(aggregateCatalog, true);
//2. As expected this is resolved
container.GetExport<MefExport>().Should().NotBeNull();
//3. Initialize Autofac
var builder = new ContainerBuilder();
builder.Register(c => new AutofacExport()).Exported(x => x.As<AutofacExport>());
builder.RegisterComposablePartCatalog(aggregateCatalog);
var ioc = builder.Build();
//4. Here Autofac is correctly providing the dependency to the mef ImportingConstructor
ioc.Resolve<MefExportWithDependency>().AutofacExport.Should().NotBeNull();
//5. The next line will throw ImportCardinalityMismatchException
container.GetExport<MefExportWithDependency>();
}
There code above expects the following classes to be defined:
public class AutofacExport { }
[Export]
public class MefExport { }
[Export]
public class MefExportWithDependency
{
public AutofacExport AutofacExport { get; set; }
[ImportingConstructor]
public MefExportWithDependency(AutofacExport autofacExport)
{
AutofacExport = autofacExport;
}
}
Note:
I have also had a look at https://www.nuget.org/packages/MefContrib.Integration.Autofac/ - which promises to integrate Mef with Autofac. However, I am not able to find relevant documentation on how to configure that, and the package does not have a lot of usage.
I think you may have misunderstood the way the Autofac.Mef package is supposed to work. While it brings MEF items into Autofac, letting Autofac understand the export/import attributes and items registered in the MEF catalogs, it's a one-way operation - it doesn't push Autofac registrations into MEF or allow a MEF CompositionContainer to use Autofac.
I believe what you want is the MefContrib.Integration.Autofac package you mentioned, which appears to allow things to flow the other direction - from Autofac into MEF.
A good place to see how it works is in their repository, where they have some unit tests showing integration where MEF is resolving Autofac items. Here's one such test:
[Test]
public void ExportProviderResolvesServiceRegisteredByTypeTest()
{
// Setup
var builder = new ContainerBuilder();
builder.RegisterType<AutofacOnlyComponent1>().As<IAutofacOnlyComponent>();
var autofacContainer = builder.Build();
var adapter = new AutofacContainerAdapter(autofacContainer);
var provider = new ContainerExportProvider(adapter);
var component = provider.GetExportedValue<IAutofacOnlyComponent>();
Assert.That(component, Is.Not.Null);
Assert.That(component.GetType(), Is.EqualTo(typeof(AutofacOnlyComponent1)));
}
As you can see, they have an adapter for Autofac containers that sort of "converts" them into something MEF can understand. They also have some unit tests showing bi-directional integration - MEF resolving from Autofac, Autofac resolving from MEF.
I've never personally used that package, but I think if you check out the tests and how they've got those set up it should get you on your way.
I have the following code running in my Application_Start method:
var builder = new ContainerBuilder();
var store = new DocumentStore { Url = "http://localhost:8081" };
store.Initialize();
builder.RegisterInstance(store);
var container = builder.Build();
I am using AutoFac to store the instance of my RavenDB DocumentStore. Now I know this only runs once when the application is started however how would I be able to access the container variable so that I can retrieve the DocumentStore that in stored in there from anywhere in my application.
The idea of DI is that you configure your container in the Application_Start and you wire all the necessary dependencies into your objects so that you never need to access the container in other parts of your code. So to answer your question: simply have the parts of your application that need to access the DocumentStore take it as constructor argument and then configure AutoFac to inject it.
Having other parts of your code depending on the container is a bad practice as they become tightly coupled to it.
Ok! As Darin pointed out, it's not a good practice but if you want to,
you could do
var container = builder.Build();
Application["container"] = container;
and access it by
var container = Application["container"] as Container; // assuming Container is the type