在ASP.NET Web API项目中,如果使用Simple Injector进行依赖项注入,它将使用以下代码行注册所有控制器:
container.RegisterWebApiControllers(
System.Web.Http.GlobalConfiguration.Configuration);
如果您在同一个项目中有Elmah记录器,那么要访问记录器,只需使用http://yourapp.com/elmah
,如下所示。
问题是Simple Injector认为elmah
是一个控制器,并产生以下错误:
找不到类型ElmahController的注册。
如果类型具有elmah
,我想配置Simple Injector以避免构造,但我不知道如何配置。
我需要做些什么来解决这个问题?
以下是完整的错误:
找不到类型ElmahController的注册。确保ElmahController已注册,例如通过调用"Container.Register();"在注册阶段。无法进行隐式注册,因为Container.Options.RResolveUnregisteredConcreteTypes设置为"false",这是v5中的默认设置。这将禁止容器构造此未注册的具体类型。有关为什么默认情况下不允许解析未注册的具体类型,以及可以应用哪些可能的修复程序的更多信息,请参阅https://simpleinjector.org/ructd.描述:在执行当前web请求期间发生未处理的异常。请查看堆栈跟踪以了解有关错误以及错误在代码中的来源的更多信息。
异常详细信息:SimpleInjector.ActivationException:找不到类型ElmahController的注册。确保ElmahController已注册,例如通过调用"Container.Register();"在注册阶段。无法进行隐式注册,因为Container.Options.RResolveUnregisteredConcreteTypes设置为"false",这是v5中的默认设置。这将禁止容器构造此未注册的具体类型。有关为什么默认情况下不允许解析未注册的具体类型,以及可以应用哪些可能的修复程序的更多信息,请参阅https://simpleinjector.org/ructd.
来源错误:
在执行当前web请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪来识别有关异常的起源和位置的信息。
堆栈跟踪:
[ActivationException:找不到类型ElmahController的注册。请确保ElmahController已注册,例如在注册阶段调用Container.Register();。无法进行隐式注册,因为Container.Options.RResolveUnregisteredConcreteTypes设置为"false",这是v5中的默认设置。这将禁止容器构造此未注册的具体类型。有关为什么默认情况下不允许解析未注册的具体类型,以及可以应用哪些可能的修复程序的更多信息,请参阅https://simpleinjector.org/ructd.]SimpleInjector.Container.ThrowNotConstructableException(类型concreteType)+138SimpleInjector.Container.ThrowMissingInstanceProducerException(类型类型)+88SimpleInjector.Container.GetInstanceForRootType(类型serviceType)+186SimpleInjector.Container.GetInstance(类型serviceType)+82System.Web.Mvc.DefaultControllerActivator.Create(RequestContext RequestContext,Type controllerType)+64
InvalidOperationException:尝试创建类型为"Elmah.Mvc.ElmahController"的控制器时出错。请确保该控制器具有无参数公共构造函数。]System.Web.Mvc.DefaultControllerActivator.Create(RequestContext RequestContext,Type controllerType)+245System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBasehttpContext,IController&controller,IContrlerFactory&factory)+267System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBasehttpContext,AsyncCallback回调,对象状态)+77System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+970System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep步骤)+75System.Web.HttpApplication.ExecuteStep(IExecutionStep步骤,Boolean和completedSynchronously)+158
好吧,我想我已经想通了。
一些注意事项
由于我已经这样配置了容器的生活方式:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
注册ElmahController
时,我无法使用LifeStyle.Scoped
。另外两个选项是LifeStyle.Singleton
和LifeStyle.Transient
。我们不想要LifeStyle.Singleton
,因为需要大量的实例,所以我们只剩下一个选项,那就是LifeStyle.Transcient
。
解决方案
您需要向Simple Injector:注册
container.Register<Elmah.Mvc.ElmahController>(Lifestyle.Transient);
上面的行将导致不同的错误:
配置无效。报告了以下诊断警告:-[一次性瞬态组件]ElmahController注册为瞬态,但实现IDisposable。
为了消除这个错误,我首先检查了ElmahController
的Dispose
方法是否有用。事实证明,它只是从System.Web.Mvc.Controller
导出的,这里是Dispose
方法:
public void Dispose()
{
Dispose(true /* disposing */);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
由于它没有任何用处,所以如果不调用它也没关系。因此,以下代码就足够了:
container.GetRegistration(typeof(Elmah.Mvc.ElmahController)).Registration
.SuppressDiagnosticWarning(
DiagnosticType.DisposableTransientComponent,
"No need to call dispose because it does nothing useful.");
RegisterWebApiControllers
扩展方法使用ASP.NET Web API的IAssembliesResolver
抽象来获取要查找控制器实例的程序集列表。
显然,ElmahController
生活在IAssembliesResolver.GetAssemblies()
未返回的程序集中。要解决这个问题,你可以做两件事:
- 调用接受
Assembly
实例列表的RegisterWebApiControllers
重载,并传入包含控制器的应用程序集+包含程序集的ELMAH程序集 - 自定义Web API的控制器发现机制,如下所述
特别是与手动注册控制器相比,第一种解决方案更简单,因为在盖子下RegisterWebApiControllers
可确保抑制一次性组件的假阳性诊断警告。