从没有 "GetInstance" 方法的简单注入器获取实例
Get Instance from Simple Injector without "GetInstance" method
在此之后 我这样做了 :
public class Log4netAdapter<T> : ILogger
{
private static readonly log4net.ILog logger = LogManager.GetLogger(typeof(T));
public void Log(LogEntry entry)
{
if(entry.LoggingEventType == LoggingEventType.Information)
logger.Info(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Warning)
logger.Warn(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Error)
logger.Error(entry.Message, entry.Exception);
else
logger.Fatal(entry.Message, entry.Exception);
}
}
然后在简单注入器上:
container.RegisterConditional(
typeof(ILogger),
c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
如果我在我需要的每个 class 构造函数上注入 ILogger,这会非常有效。我的问题是我有一些无法使用构造函数注入的 classes。对于这种情况,我通常会这样做:
var logger = SimpleInjectorInitializer.Container.GetInstance<ILogger>();
但是上面的方法不起作用,它在简单注入器 class 上抛出错误,因为 c.Consumer
是 null
。
这是我需要解决的例子之一 ILogger
,这个 class 是在 webapi 启动 class 上注册的。
public class ExceptionWebApiHandlingAttribute : IExceptionFilter
{
public ExceptionWebApiHandlingAttribute()
{
}
}
还有其他选择吗?
谢谢
在应用程序边界上工作时,有时很难或不可能使用构造函数注入。典型示例是 MVC 过滤器属性或 ASP.NET Web 窗体 Page
class 需要默认构造函数的元素。
这些问题的典型解决方案是将这样的边界class做成一个Humble Object,所有有趣的逻辑都从边界class中提取到一个组件中。边界 class 应该只包含对服务定位器的调用,并在已解析的服务上调用一个方法。这最大限度地减少了应用程序中不可测试的代码量。
在所有其他情况下,构造函数注入应该是首选。
然而,您解析 ILogger
的事实意味着您的边界 class 做的太多了。相反,此 ILogger
应该是您从边界 class 中提取的组件的构造函数依赖项,以成为一个不起眼的对象。
完成此操作后,您将不再直接解析 ILogger
,这将解决您的问题; ILogger
已成为消费者的依赖项,这确保了 Simple Injector 能够代表您构建正确的 Logger<T>
。
在 Web API(您的特定情况)中将依赖项应用于异常过滤器时,一个好的解决方案是为您的异常过滤器创建一个代理,它将调用委托给真正的过滤器解决。这可能是一些基础设施,并且解释了这个概念 here。
如果无法应用上述建议,无论出于何种原因,您始终可以直接从容器中请求 Logger<T>
:
ILogger log = SimpleInjectorInitializer.Container.GetInstance<Logger<MyHumbleObject>>();
在此之后
public class Log4netAdapter<T> : ILogger
{
private static readonly log4net.ILog logger = LogManager.GetLogger(typeof(T));
public void Log(LogEntry entry)
{
if(entry.LoggingEventType == LoggingEventType.Information)
logger.Info(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Warning)
logger.Warn(entry.Message, entry.Exception);
else if(entry.LoggingEventType == LoggingEventType.Error)
logger.Error(entry.Message, entry.Exception);
else
logger.Fatal(entry.Message, entry.Exception);
}
}
然后在简单注入器上:
container.RegisterConditional(
typeof(ILogger),
c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
如果我在我需要的每个 class 构造函数上注入 ILogger,这会非常有效。我的问题是我有一些无法使用构造函数注入的 classes。对于这种情况,我通常会这样做:
var logger = SimpleInjectorInitializer.Container.GetInstance<ILogger>();
但是上面的方法不起作用,它在简单注入器 class 上抛出错误,因为 c.Consumer
是 null
。
这是我需要解决的例子之一 ILogger
,这个 class 是在 webapi 启动 class 上注册的。
public class ExceptionWebApiHandlingAttribute : IExceptionFilter
{
public ExceptionWebApiHandlingAttribute()
{
}
}
还有其他选择吗?
谢谢
在应用程序边界上工作时,有时很难或不可能使用构造函数注入。典型示例是 MVC 过滤器属性或 ASP.NET Web 窗体 Page
class 需要默认构造函数的元素。
这些问题的典型解决方案是将这样的边界class做成一个Humble Object,所有有趣的逻辑都从边界class中提取到一个组件中。边界 class 应该只包含对服务定位器的调用,并在已解析的服务上调用一个方法。这最大限度地减少了应用程序中不可测试的代码量。
在所有其他情况下,构造函数注入应该是首选。
然而,您解析 ILogger
的事实意味着您的边界 class 做的太多了。相反,此 ILogger
应该是您从边界 class 中提取的组件的构造函数依赖项,以成为一个不起眼的对象。
完成此操作后,您将不再直接解析 ILogger
,这将解决您的问题; ILogger
已成为消费者的依赖项,这确保了 Simple Injector 能够代表您构建正确的 Logger<T>
。
在 Web API(您的特定情况)中将依赖项应用于异常过滤器时,一个好的解决方案是为您的异常过滤器创建一个代理,它将调用委托给真正的过滤器解决。这可能是一些基础设施,并且解释了这个概念 here。
如果无法应用上述建议,无论出于何种原因,您始终可以直接从容器中请求 Logger<T>
:
ILogger log = SimpleInjectorInitializer.Container.GetInstance<Logger<MyHumbleObject>>();