使用WebApi,SimpleInjector和MediatR时正确设置Scope

时间:2016-09-22 14:40:03

标签: c# asp.net-web-api simple-injector mediatr

控制器

public class LocationsController : ApiController
{
    private readonly IMediator _mediator;

    public LocationsController(IMediator mediator)
    {
        _mediator = mediator;
    }

    public IEnumerable<Place> Get()
    {
        return _mediator.Send(new GetLatestMapData<Place>());
    }
}

在第一次请求Get()动作时,Handler由SimpleInjector实例化并正确执行。

在第二个请求(例如浏览器中的F5)中,它失败并显示:

  

对于类型请求没有找到处理程序....

     

未正确配置容器或服务定位器或未在容器中注册处理程序。

和内部例外:

  

无法访问已处置的对象。

     

对象名称:'ThreadLocal对象已被释放。'

OWIN初创公司

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // SimpleInjector
        var container = CompositionRoot.CreateContainer();

        var config = GlobalConfiguration.Configuration;

        config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

        // Routing
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}",
            new { id = RouteParameter.Optional });

        config.EnsureInitialized();

        app.UseWebApi(config);
    }
}

用于WebAPI项目的SimpleInjector IPackage

public class Installer : IPackage
{
    public void RegisterServices(Container c)
    {
        c.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

        c.RegisterWebApiControllers(GlobalConfiguration.Configuration);
    }
}

我认为正在发生的事情是正确创建了Handler,然后在第一个请求之后处理。 现在,我不知道为什么,但在后续请求中,不会重新创建Handler。我知道这一点,因为如果我将WebApiRequestLifestyle更改为“在范围结束时不进行处理”,则它适用于每个请求:

c.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle(false
/*disposeInstanceWhenScopeEnds*/);

问题

  1. 我应该将disposeInstanceWhenScopeEnds参数设置为false吗?
  2. 如果没有,那么正确的解决方案是什么?
  3. 我看到这是solved before by creating a LifetimeScopeDecorator ...但是,SimpleInjector WebApi集成库已经提供了这个功能吗?我错过了什么?
  4. (谢谢你阅读)

2 个答案:

答案 0 :(得分:0)

这个link为依赖解析和使用IDependencyResolver / IDependencyScope接口提供了很好的指导。

你会立刻看到他们触及的生命跨度往往会有点棘手。

本节特别有趣:

  

依赖范围和控制器寿命

     

根据请求创建控制器。要管理对象的生命周期,   IDependencyResolver使用范围的概念。

     

附加到HttpConfiguration对象的依赖项解析器具有   全球范围。当Web API创建控制器时,它会调用BeginScope。   此方法返回表示子范围的IDependencyScope。

     

Web API然后在子范围上调用GetService来创建   控制器。请求完成后,Web API将调用Dispose   儿童范围。使用Dispose方法处理控制器   的依赖关系。

在应用启动过程中,传统的引导服务会发生一次,因为您知道在那时解决任何依赖关系。只有当工作进程关闭时(例如,没有活动),才会调用dispose。

通常我认为解决的实例保留生命周期是很正常的,除非它们必须在使用后被销毁。但是给出的例子解释了我们必须在请求完成后正确处理。因此,我建议您使用提供的示例正确处理您的实例。

这在使用IoC和WebApi时帮助了我。我希望这有帮助!

答案 1 :(得分:0)

您需要安排您的终身范围

代码:

container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

container.Options.LifestyleSelectionBehavior = new WebApiInjectionLifestyle();


internal class WebApiInjectionLifestyle : ILifestyleSelectionBehavior
{
    public Lifestyle SelectLifestyle(Type serviceType, Type implementationType)
    {
        return Lifestyle.Scoped;
    }
}

更多细节

https://simpleinjector.readthedocs.io/en/latest/lifetimes.html