c# - 如果无法进行依赖注入(inject)怎么办?

标签 c# asp.net dependency-injection dependency-management service-locator

经过多次踢打和尖叫之后,我开始接受 DI,尽管随着依赖性的增长,SL 看起来更加清晰。

但是,IMO 在 DI 方面仍然存在重大障碍:

当您无法控制对象的实例化时,DI 是不可能的。在 ASP.NET 世界中,示例包括:HttpModule、HttpHandler、Page 等。

在上面的场景中,我们将求助于静态服务位置来解决依赖关系,通常是通过 HttpContext.Current,它总是从当前线程推断范围。因此,如果我们要在这里使用静态 SL,那么为什么不在其他地方也使用它呢?

答案是否简单到:咬紧牙关,在必要时使用 SL(如上),但尽量偏爱 DI?如果是这样:只使用一次静态 SL 不会破坏整个应用程序的一致性吗?从本质上消除 DI 在其他地方的辛勤工作?

最佳答案

有时您无法避免紧耦合,就像在您的示例中一样。但是,这并不意味着您也需要接受它。相反,通过封装困惑并将其从您的日常生活中分离出来来隔离它。

例如,如果我们想要当前的 Forms 身份验证用户,我们别无选择,只能访问 HttpContext.Current.Request.User.Identity.Name。但是,我们确实可以选择在哪里进行调用。

HttpContext.Current 是一个问题的解决方案。当我们直接从我们使用结果的地方调用它时,我们是在同一个地方声明问题和解决方案:“我需要当前用户名,它被坚定地声明为来自当前 HTTP 上下文。”这混淆了两者的定义,并且不允许对同一问题有不同的解决方案。

我们缺少的是对我们正在解决的问题的清晰表述。对于这个例子,它会是这样的:

Determine the user which made the current request

我们正在使用 HttpContext.Current 甚至用户名这一事实并不是核心问题定义的一部分;它是一个实现细节,只会使需要当前用户的代码复杂化。

我们可以通过接口(interface)表示检索当前用户的意图,没有实现细节:

public interface IUserContext
{
    User GetUser();
}

我们直接调用 HttpContext.Current 的任何类现在都可以改用这个由容器注入(inject)的接口(interface),以保持 DI 的良好状态。对于一个类来说,在其构造函数中接受 IUserContext 比具有无法从其公共(public) API 中看到的依赖项更能揭示意图。

实现将静态调用隐藏在一个地方,它不会再伤害我们的对象:

public class FormsUserContext : IUserContext
{
    private readonly IUserRepository _userRepository;

    public FormsUserContext(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public User GetUser()
    {
        return _userRepository.GetByUserName(HttpContext.Current.Request.User.Identity.Name);
    }
}

关于c# - 如果无法进行依赖注入(inject)怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5060353/

相关文章:

C# 注册表子键双字值

asp.net - 使用 ASP.NET 进行 Paypal 订阅的代码示例

c++ - 在 C++ 中使用接口(interface)进行依赖注入(inject)

php - 通过服务将 Symfony EntityManager 注入(inject)到表单类型中

c# - 在不使用错误处理的情况下监视 c# web 服务的状态

c# - 使用 Try-Catch 处理看到的错误,不好吗?

c# - 跨表SQL查询

asp.net - 'Microsoft.Jet.OLEDB.4.0' 提供程序未在本地计算机上注册

c# - ASP.Net、C#.Net 和 VB.Net 之间的区别?

configuration - StructureMap HowTo:深对象的条件构造