I need to get or access to my IoC container in a static class. This is my (simplified) scenario:
I register dependencies for ASP .net Web Api in a Startup class (but also I do this for MVC or WCF. I have a DependecyResolver project, but for simplicity, consider the following code)
// Web Api project - Startup.cs
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
var builder = new ContainerBuilder();
// ... Omited for clarity
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof(IHandle<>))
.AsImplementedInterfaces();
// ...
IContainer container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// ...
}
Then, in a separate class library I have my static class (again simplified for clarity):
public static class DomainEvents
{
private static IContainer Container { get; set; }
static DomainEvents()
{
//Container = I need get my Autofac container here
}
public static void Register<T>(Action<T> callback) where T : IDomainEvent { /* ... */ }
public static void ClearCallbacks() { /* ... */ }
public static void Raise<T>(T args) where T : IDomainEvent
{
foreach (var handler in Container.Resolve<IEnumerable<IHandle<T>>>())
{
handler.Handle(args);
}
// ...
}
}
Any idea how can I get this?
I need to get or access to my IoC container in a static class. Any idea how can I get this?
Yes, you don't! Seriously. The pattern with the static DomainEvents
class originates from Udi Dahan, but even Udi has admitted that this was a bad design. Static classes that require dependencies of their own are extremely painful to work with. They make the system hard to test and maintain.
Instead, create a IDomainEvents
abstraction and inject an implementation of that abstraction into classes that require publishing events. This completely solves the your problem.
You can define your DomainEvents
class as follows:
public interface IDomainEvents
{
void Raise<T>(T args) where T : IDomainEvent;
}
// NOTE: DomainEvents depends on Autofac and should therefore be placed INSIDE
// your Composition Root.
private class AutofacDomainEvents : IDomainEvents
{
private readonly IComponentContext context;
public AutofacDomainEvents(IComponentContext context) {
if (context == null) throw new ArgumentNullException("context");
this.context = context;
}
public void Raise<T>(T args) where T : IDomainEvent {
var handlers = this.context.Resolve<IEnumerable<IHandle<T>>>();
foreach (var handler in handlers) {
handler.Handle(args);
}
}
}
And you can register this class as follows:
IContainer container = null;
var builder = new ContainerBuilder();
builder.RegisterType<AutofacDomainEvents>().As<IDomainEvent>()
.InstancePerLifetimeScope();
// Other registrations here
container = builder.Build();
You can create a static method inside your DomainEvents
class to inject the container like this:
public static class DomainEvents
{
public static void SetContainer(IContainer container)
{
Container = container;
}
....
}
And then from your ASP.NET application, call this method to inject the container:
DomainEvents.SetContainer(container);
Please note that I am giving you a direct answer to your question. However, here are some issues that I see with this:
- Static classes should not be used when the class requires dependencies. In such case, refactor to use a non-static class and use Constructor Injection to inject the dependencies that you need in the class.
- Using the container outside of the Composition Root is called Service Location and is considered an anti-pattern.
- Class libraries should not use the container or even have a Composition Root. Quoting from the Composition Root article that I referenced:
Only applications should have Composition Roots. Libraries and frameworks shouldn't.
来源:https://stackoverflow.com/questions/33955182/access-or-get-autofac-container-inside-a-static-class