WebAPI:访问子容器作为服务定位器

时间:2012-10-30 16:40:48

标签: asp.net-web-api unity-container ioc-container service-locator

在普通的ASP.MVC项目中,我们使用Unity配置依赖项解析程序,并使用http://unitymvc3.codeplex.com/

中的Unity.Mvc3程序包

我们已经使用HierarchicalLifetimeManager

注册了此测试服务
container.RegisterType<ITestService, TestService>(new HierarchicalLifetimeManager());

我们在Global.asax.cs中用Mvc连接容器:

System.Web.Mvc.DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(container));

我们运行这个测试控制器:

public class TestController : Controller
{
    private readonly ITestService _service;
    public TestController(ITestService service)
    {
        this._service = service;
    }
    public ActionResult Test()
    {
        var locatedService = System.Web.Mvc.DependencyResolver.Current.GetService<ITestService>();
        if (_service == locatedService)
            return View("Success - Same Service");//This is always the result in an MVC controller
        else
            throw new Exception("Failure - Different Service Located");//This is never the result in an MVC controller
    }
}

但是,在这个项目中,我们添加了许多WebAPI控制器。

我们现在在global.asax.cs中使用此配置(暂时使用http://unitywebapi.codeplex.com/。但我愿意接受建议):

System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);

我们创建的ApiTestController类似于TestController,继承自ApiController而不是Controller。 但是,ApiTestController未通过测试。我知道System.Web.Mvc.DependencyResolver类和System.Web.Mvc.DependencyResolver.Current属性是特定于Mvc的。但是,WebAPI是否具有同等效力?

System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService不起作用,因为System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver实例是我配置的父容器。它不是用于将ITestService注入构造函数的子控制器。

此用户似乎遇到了类似的问题:http://unitywebapi.codeplex.com/discussions/359413 但我觉得这可能与ASP.NET的WebAPI有关,而不是与Unity有关。

由于

3 个答案:

答案 0 :(得分:2)

在查看了http://unitymvc3.codeplex.com/http://unitywebapi.codeplex.com/的来源后,我创建了这个类:

public class MyUnityDependencyResolver : Unity.Mvc3.UnityDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver
{
    public MyUnityDependencyResolver(IUnityContainer container)
        : base(container)
    {
    }

    public System.Web.Http.Dependencies.IDependencyScope BeginScope()
    {
        return this;
    }

    public void Dispose()
    {
        Unity.Mvc3.UnityDependencyResolver.DisposeOfChildContainer();
    }
}

gobal.asax.cs中的配置:

var myResolver = new MyUnityDependencyResolver(container);
System.Web.Mvc.DependencyResolver.SetResolver(myResolver);
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = myResolver;

Unity.Mvc3.UnityDependencyResolver使用HttpContext.Current.Items来管理子容器。 MyUnityDependencyResolver可能不是System.Web.Http.Dependencies.IDependencyResolver最“正确”的实现,但到目前为止似乎有效。

如果没有其他人有更好的答案,我会在几天内将此标记为答案。

答案 1 :(得分:1)

不幸的是,当您调用GlobalConfiguration.Configuration.DependencyResolver.GetService时,它会完全忽略任何作用域并使用外部非子容器进行解析,该容器在应用程序的生命周期内存在。这是Web Api的一个问题,因此无法对控制器之外的每个请求依赖项使用构造函数注入。令人困惑的是,这与MVC完全不同,就像你说的那样。

您可以使用HttpRequestMessage的GetDependencyScope()扩展方法。当您将HierarchicalLifetimeManager与Unity.WebApi结合使用时,使用此功能解决的任何问题都将在每个请求范围内。该请求可以从操作过滤器和处理程序获得,因此可能是一种可行的解决方法。

显然这是纯服务位置而不是依赖注入,这远非理想,但我还没有找到另一种方法来访问控制器之外的每个请求依赖项。

有关详细信息,请参阅this post

答案 2 :(得分:0)

DependencyResolver不是ASP.NET WebAPI中依赖注入的正确接缝。

Mark Seemann在使用WebAPI的DI上有两篇非常好的帖子。

Dependency Injection and Lifetime Management with ASP.NET Web API

Dependency Injection in ASP.NET Web API with Castle Windsor

如果你想做得对,你应该看看它们。