【问题标题】:Unity DI: Resolving from per-request to global singleton to per-requestUnity DI:从每个请求解析到全局单例到每个请求
【发布时间】:2018-02-19 12:01:13
【问题描述】:

我有一个控制器调用全局单例,在 ASP.NET WebAPI 的上下文中调用每个请求实例。基本上

每个请求 => 单例 => 每个请求

以下设置是否正确?我特别担心第二个 per-request 实例,因为它可能是基于用户的声明。

或者反模式和单例应该从控制器接收(每个请求)依赖项?

    // UnityConfig.cs, the Resolver uses CreateChildContainer()
    public static void RegisterTypes(IUnityContainer unity)
    {
        // global singleton
        unity.RegisterType<MessageContext>(new ContainerControlledLifetimeManager());
        // instance per request
        unity.RegisterType<ClaimsContext>(new HierarchicalLifetimeManager());
    }

    // API controller
    public class MyController : ApiController
    {
        private readonly MessageContext _message;

        public FormController(MessageContext message)
        {
            _message = message;
        }

        public Task<IHttpActionResult> MyAction()
        {
            _message.FireAndForget();
            return Ok();
        }
    }

    // global singleton to keep connection pool
    public class MessageContext
    {
        private readonly IUnityContainer _unity;

        public MessageContext(IUnityContainer unity)
        {
            _unity = unity;
        }

        public Task FireAndForget()
        {
            // resolve per request
            var claim = _unity.Resolve<ClaimsContext>().MyClaim);
            // ...
        }
    }

【问题讨论】:

  • 这个问题,如果对_unity.Resolve 的调用能正确解决,仍然存在,但我猜它是臭代码。重构可能是最好的!
  • 正如博客文章所解释的,消费者将在消费者的生命周期内保持其依赖关系。这意味着,如果您在单例中注入 per-request,per-request 依赖项将在请求中继续存在,这几乎总是会导致意想不到的后果(现在或将来)。防止出现这种情况,并找到一种方法来使用单元测试来检测这些类型的错误(或切换到开箱即用为您检测这些类型问题的容器)。
  • 明白这一点,而且很明显上面的代码设计得不好,但是ClaimsContext 是手动解决的,而不是构造函数注入,而不是在MessageContext 的私有属性中。引用仅在FireAndForget 调用期间有效。那么你所说的在那种情况下仍然适用吗?博文 afaik 中没有提到这种情况。
  • 您在 MessageContext 中应用 Service Locator anti-pattern,这也很糟糕。您应该同时阻止服务定位器和强制依赖项。

标签: c# asp.net asp.net-web-api dependency-injection unity-container


【解决方案1】:

正如 cmets 中所指出的,上面的示例代码需要重新构建。为了解决这个问题,我将MessageContext 拆分为长寿命和短寿命部分。短寿命部分接收短寿命ClaimsContext,而长寿命部分只保留长寿命连接。

【讨论】:

    猜你喜欢
    • 2012-06-15
    • 1970-01-01
    • 2014-09-04
    • 2015-04-11
    • 2012-02-18
    • 1970-01-01
    • 2012-01-04
    • 2010-11-12
    • 1970-01-01
    相关资源
    最近更新 更多