You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:33:18