【问题标题】:Access HttpContext in constructor for fake DI在构造函数中访问假 DI 的 HttpContext
【发布时间】:2018-06-02 09:29:48
【问题描述】:

我正在开发一个尚未进行 DI 或单元测试的 asp.net mvc 应用程序。因此,我开始通过将应用程序拆分为 3 层来重组应用程序以进行单元测试:控制器 - 服务 - 数据访问。

一些控制器使用 Session 和 Cookie 来存储和检索值。所以我创建了一个接口和一个类来处理从 Session 和 Cookie 中保存和检索值。

我只是通过使用单元测试来做到这一点,从不运行应用程序。

由于应用程序没有 DI,因此我通过将控制器的 HttpContext 作为输入参数在控制器的构造器上创建了 ContextService。

但是,当我运行应用程序时,这些值没有被检索或保存在会话或 Cookie 中。似乎 HttpContext 在构造函数上为空。

问题 1: 我应该如何处理我的 ContextService。它应该使用静态属性 HttpContext.Current 来访问会话和 cookie(如何进行单元测试)还是...?

问题 2: 如果您知道另一种解决方案,应该如何适应它以便将来也有 DI。

【问题讨论】:

    标签: c# asp.net-mvc dependency-injection httpcontext


    【解决方案1】:

    我通过将控制器的 HttpContext 作为输入参数,在控制器的构造器上创建了 ContextService。

    通过将HttpContext 从控制器传递到服务,您可以让控制器负责创建该服务。这将控制器与服务紧密耦合,而松散耦合是目标。

    是否应该使用静态属性 HttpContext.Current 来访问会话和 cookie

    如何进行单元测试

    不会的。这是我们创建抽象的一个重要原因。我们系统中的某些部分无法进行单元测试,我们希望能够用我们在测试中使用的假实现来替换它们。

    然而,诀窍是使被替换的部分尽可能小,最好不要将其与业务逻辑混合,因为替换也意味着您不会测试该逻辑。

    您应该在抽象后面隐藏对HttpContext.Current 的访问。但是当您这样做时,请确保以最适合您的应用程序的方式定义抽象。例如,仔细看看你的ContextService 想要什么。它真的要访问 cookie 吗?可能不是。还是它想要当前登录用户的名称或 ID?这更有可能。所以你应该围绕它来建模你的抽象。

    例如,定义一个抽象,允许应用程序代码使用 IUserContext 访问有关登录用户的信息:

    public interface IUserContext
    {
        string UserName { get; }
    }
    

    此抽象的一种可能实现是从 HTTP cookie 中检索此信息:

    public class CookieUserContext : IUserContext
    {
        public string UserName => HttpContext.Current.Cookies["name"];
    }
    

    但是您可以轻松想象其他实现方式,例如,当相同的应用程序代码需要在 Web 请求的上下文之外运行时,例如作为后台操作的一部分,或隔离的 Windows 服务应用程序。这是引入抽象的另一个重要原因——当相同的代码需要能够在不同的环境中运行时。

    如果您有兴趣,Mark Seemann 所著的《Dependency Injection in .NET》一书非常详细地介绍了这类模式和原则,例如应用 DI 的原因、防止紧耦合。由 Seemann 和我本人撰写的 second edition of this book 甚至更详细地介绍了您正在努力解决的问题,例如防止泄漏抽象、如何将行为分成类以及使用 SOLID 原则设计应用程序。本书首页包含第一章的下载链接,可免费下载。

    【讨论】:

    • 所以基本上你证实了我最初使用静态 HttpContext.Current 的怀疑。您能否确认没有其他方法可以使用 DI 创建 CookieUserContext 来注入 HttpContext。我想对此进行单元测试的原因是因为我想对所有服务进行单元测试。
    • 总有替代方案。但他们是否值得付出努力是你应该问自己的。 IMO,这不值得,只要您使 thoae 适配器非常纤薄。而且不管有多少单元测试,你仍然需要进行一些集成测试。
    猜你喜欢
    • 2017-11-24
    • 2015-08-07
    • 2018-04-04
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多