在构造函数中访问HttpContext以获取假DI

我正在一个还没有DI或单元测试的asp.net mvc应用程序上工作。因此,我开始通过将应用程序划分为3个层来重组应用程序以进行单元测试:Controllers-Services-DataAccess。

一些控制器正在使用Session和Cookies来存储和检索值。因此,我创建了一个接口和一个类来处理从Session和Cookies中保存和检索值的问题。

我仅通过使用单元测试来执行此操作,而从未运行过该应用程序。

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

但是,当我运行应用程序时,未在Session或Cookies中检索或保存值。看来HttpContext在构造函数上为null。

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

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

史蒂文

我通过提供控制器的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撰写的《.NET中的依赖注入》一书将详细介绍这些类型的模式和原理,例如应用DI的原因,防止紧密耦合。本书第二版,由Seemann和我本人撰写,甚至更详细地介绍了您正在苦苦挣扎的事情,例如防止泄漏抽象,如何将行为分离为类以及使用SOLID原理设计应用程序。本书的首页包含第一章的下载链接,可以免费下载。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章