在静态 class 中访问或获取 Autofac 容器
Access or get Autofac Container inside a static class
我需要在静态 class 中获取或访问我的 IoC 容器。这是我的(简化的)场景:
我在 Startup class 中为 ASP .net Web Api 注册依赖项(但我也为 MVC 或 WCF 这样做。我有一个 DependecyResolver 项目,但为了简单起见, 考虑以下代码)
// 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);
// ...
}
然后,在一个单独的 class 库中,我有我的静态 class(为清楚起见再次简化):
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);
}
// ...
}
}
知道我怎样才能得到这个吗?
您可以在 DomainEvents
class 中创建一个静态方法来像这样注入容器:
public static class DomainEvents
{
public static void SetContainer(IContainer container)
{
Container = container;
}
....
}
然后从您的 ASP.NET 应用程序调用此方法注入容器:
DomainEvents.SetContainer(container);
请注意,我将直接回答您的问题。但是,这里有一些我看到的问题:
当 class 需要依赖项时,不应使用 - 静态 classes。在这种情况下,重构以使用非静态 class 并使用构造函数注入将所需的依赖项注入 class.
- 使用 Composition Root is called Service Location and is considered an anti-pattern 之外的容器。
- Class 库不应该使用容器,甚至不应该有合成根。引用我引用的 Composition Root 文章:
Only applications should have Composition Roots. Libraries and frameworks shouldn't.
I need to get or access to my IoC container in a static class.
Any idea how can I get this?
是的,你没有!严重地。 static DomainEvents
class 的图案起源于Udi Dahan,但Udi 也承认这是一个糟糕的设计。静态 classes 需要自己的依赖关系,使用起来非常痛苦。它们使系统难以测试和维护。
相反,创建一个 IDomainEvents
抽象并将该抽象的实现注入到需要发布事件的 classes 中。这完全解决了你的问题。
您可以按如下方式定义您的 DomainEvents
class:
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);
}
}
}
并且您可以按如下方式注册此class:
IContainer container = null;
var builder = new ContainerBuilder();
builder.RegisterType<AutofacDomainEvents>().As<IDomainEvent>()
.InstancePerLifetimeScope();
// Other registrations here
container = builder.Build();
我需要在静态 class 中获取或访问我的 IoC 容器。这是我的(简化的)场景:
我在 Startup class 中为 ASP .net Web Api 注册依赖项(但我也为 MVC 或 WCF 这样做。我有一个 DependecyResolver 项目,但为了简单起见, 考虑以下代码)
// 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);
// ...
}
然后,在一个单独的 class 库中,我有我的静态 class(为清楚起见再次简化):
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);
}
// ...
}
}
知道我怎样才能得到这个吗?
您可以在 DomainEvents
class 中创建一个静态方法来像这样注入容器:
public static class DomainEvents
{
public static void SetContainer(IContainer container)
{
Container = container;
}
....
}
然后从您的 ASP.NET 应用程序调用此方法注入容器:
DomainEvents.SetContainer(container);
请注意,我将直接回答您的问题。但是,这里有一些我看到的问题:
-
当 class 需要依赖项时,不应使用
- 静态 classes。在这种情况下,重构以使用非静态 class 并使用构造函数注入将所需的依赖项注入 class.
- 使用 Composition Root is called Service Location and is considered an anti-pattern 之外的容器。
- Class 库不应该使用容器,甚至不应该有合成根。引用我引用的 Composition Root 文章:
Only applications should have Composition Roots. Libraries and frameworks shouldn't.
I need to get or access to my IoC container in a static class. Any idea how can I get this?
是的,你没有!严重地。 static DomainEvents
class 的图案起源于Udi Dahan,但Udi 也承认这是一个糟糕的设计。静态 classes 需要自己的依赖关系,使用起来非常痛苦。它们使系统难以测试和维护。
相反,创建一个 IDomainEvents
抽象并将该抽象的实现注入到需要发布事件的 classes 中。这完全解决了你的问题。
您可以按如下方式定义您的 DomainEvents
class:
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);
}
}
}
并且您可以按如下方式注册此class:
IContainer container = null;
var builder = new ContainerBuilder();
builder.RegisterType<AutofacDomainEvents>().As<IDomainEvent>()
.InstancePerLifetimeScope();
// Other registrations here
container = builder.Build();