使用Simple Injector+OWIN自托管时,container.Verify()提前实例化控制器问题
问题解决:Simple Injector + OWIN 控制器提前实例化触发异常
问题背景
使用Simple Injector搭配OWIN自托管WebApi时,出现以下问题:
- 调用
container.Verify()时,框架会创建所有控制器实例,触发部分控制器构造函数中的集成启用检查逻辑,抛出"Sample Integration is not enabled! Enable it to access the route."异常。 - 即使移除
container.Verify(),首次调用任意端点时仍会初始化所有控制器,同样触发该异常。
需要实现控制器仅在对应路由被实际访问时才实例化的效果。
解决方案
方案1:将集成检查逻辑移出构造函数(推荐)
控制器构造函数的职责应仅为依赖注入,不应包含业务校验或启用状态检查逻辑。将检查逻辑移至Action方法或统一使用Action过滤器处理。
方式1:直接移至Action方法
修改控制器代码,把检查逻辑放到具体的Action中:
[RoutePrefix("api/SampleIntegration")] [SwaggerResponse(HttpStatusCode.BadRequest, "Business Logic error", typeof(BusinessExceptionResponse))] [SwaggerResponse(422, "Invalid Entity", typeof(CamposInvalidosExceptionResponse))] public class SampleIntegrationController : ApiController { private readonly IMyService _myService; public SampleIntegrationController(IMyService myservice) { _myService = myservice; // 移除构造函数中的检查代码 } [HttpGet] public HttpResponseMessage Get() { // 在Action执行前检查集成状态 if (!_myService.IntegrationEnabled()) throw new BusinessException("Sample Integration is not enabled! Enable it to access the route."); return CreateResponse(() => _myService.GetData()); } }
方式2:使用Action过滤器统一处理
创建通用的检查过滤器,可复用在多个控制器/Action上:
public class IntegrationEnabledAttribute : ActionFilterAttribute { private readonly IMyService _myService; public IntegrationEnabledAttribute(IMyService myService) { _myService = myService; } public override void OnActionExecuting(HttpActionContext actionContext) { if (!_myService.IntegrationEnabled()) { actionContext.Response = actionContext.Request.CreateErrorResponse( HttpStatusCode.Forbidden, "Sample Integration is not enabled! Enable it to access the route."); } base.OnActionExecuting(actionContext); } }
注册并应用过滤器:
// 在ConfigureDI方法中注册过滤器到WebApi配置 config.Filters.Add(new IntegrationEnabledAttribute(container.GetInstance<IMyService>())); // 或直接标记在控制器上 [RoutePrefix("api/SampleIntegration")] [IntegrationEnabled] public class SampleIntegrationController : ApiController { // ... }
方案2:调整Simple Injector的验证逻辑
如果必须保留构造函数中的检查,可修改验证方式,避免提前实例化控制器:
修改ConfigureDI方法,将全局验证改为仅验证已注册的非控制器服务:
private void ConfigureDI(Container container, HttpConfiguration config) { // 现有注册代码... container.Register<ILinearLogger>( () => new Logger(new LinearLoggerConfiguration() { Path = PathFinder.GetLogsFilePath() }), Lifestyle.Transient); container.Register<IMyService, MyService>(); Integrations.Setup.Register(container); container.RegisterWebApiControllers(config); config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container); // 仅验证已注册的服务,跳过控制器的提前实例化 container.Verify(VerificationOption.VerifyOnlyRegisteredServices); }
注意:此方式会降低容器验证的完整性,可能遗漏部分依赖问题,仅建议作为临时方案。
方案3:自定义控制器激活器
实现IHttpControllerActivator,控制控制器的实例化时机,确保仅在路由匹配时创建实例:
public class LazyControllerActivator : IHttpControllerActivator { private readonly Container _container; public LazyControllerActivator(Container container) { _container = container; } public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { // 可在此添加路由匹配检查逻辑,确保仅当当前请求匹配该控制器路由时才实例化 return (IHttpController)_container.GetInstance(controllerType); } }
在WebApi配置中替换默认激活器:
// 在ConfigureDI方法中添加 config.Services.Replace(typeof(IHttpControllerActivator), new LazyControllerActivator(container));
内容的提问来源于stack exchange,提问作者Matheus Hoske
相关产品推荐
相关产品推荐

