从没有 "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.Consumernull

这是我需要解决的例子之一 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>>();