ASP.NET MVC:HTTPContext和依赖注入

ASP.NET MVC: HTTPContext and Dependency Injection

当前,我有一个ActionFilter,它从HttpContext获取当前用户名,并将其传递给在服务方法上使用它的操作。 例如:

1
Service.DoSomething(userName);

现在,我有一个理由不在操作级别而是在控制器构造函数级别执行此操作。 目前,我正在使用结构图来创建控制器并注入服务。 我在看类似的东西:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface IUserProvider
{
    string UserName { get; }
}

public class HttpContextUserProvider : IUserProvider
{
    private HttpContext context;

    public HttpContextUserProvider(HttpContext context)
    {
        this.context = context;
    }

    public string UserName
    {
        get
        {
            return context.User.Identity.Name;
        }
    }
}

就是说,我的IoC foo确实很弱,因为这是我使用它的第一个项目。

所以我的问题是...如何告诉结构映射在HttpContextUserProvider的构造函数中传递HttpContext? 这似乎很奇怪……我不确定如何思考HttpContext。


听起来您应该使用HttpContextBase而不是HttpContextUserProvider。这是HttpContext的现成的抽象,它允许您创建模拟,编写UnitTests并注入依赖项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SomethingWithDependenciesOnContext
{
    public SomethingWithDependenciesOnContext(HttpContextBase context) {
        ...
    }

    public string UserName
    {
        get {return context.User.Identity.Name;}
    }
}

ObjectFactory.Initialize(x =>
          x.For<HttpContextBase>()
          .HybridHttpOrThreadLocalScoped()
          .Use(() => new HttpContextWrapper(HttpContext.Current));

有一个接口摘要HttpContext.Current。仅公开您需要的方法。例如,GetUserName()将在实现中调用HttpContext.Current.User.Identity.Name。使它尽可能薄。

采用该抽象并将其注入到其他提供程序类中。这将允许您通过模拟http上下文抽象来测试提供程序。作为附带的好处,除了模拟它外,您还可以使用HttpContext抽象来做其他漂亮的事情。重用它,一方面。将常规类型参数添加到包等中。


我不确定你为什么要打扰。似乎仅在HttpContextUserProvider中直接使用HttpContext.Current是正确的选择。您永远不会用其他HttpContext替代...


也许我遗漏了一些东西,但是上面的答案对我不起作用(自从被删除以来,尽管它仍然是一个有用的答案,但它显示了如何告诉SM传递构造函数参数)。相反,如果我这样做:

1
2
3
4
5
6
7
ObjectFactory.Initialize(x =>
{
    x.BuildInstancesOf<HttpContext>()
         .TheDefault.Is.ConstructedBy(() => HttpContext.Current);
    x.ForRequestedType<IUserProvider>()
         .TheDefault.Is.OfConcreteType<HttpContextUserProvider>();
});

我懂了。我在找到之后进行了此操作:如果您在StructureMap中需要某些东西,但是您无法使用new()构建它…

编辑:

多亏了Brad的回答,我认为我对HttpContext有更好的了解。他的回答肯定有效,我只是不确定我是否喜欢在类中调用HttpContext.Current(似乎它隐藏了依赖关系,但是我对这方面的知识还很遥远)。

据我所知,以上代码应该可以注入HttpContext。 Matt Hinze提出了一个补充点,即如果HttpContext我需要的只是User.Identity.Name,则我的设计应该是明确的(在HttpContext周围有一个接口仅显示我的需要)。我认为这是个好主意。

事情是在午餐时,我有点意识到我的服务确实只需要依赖一个字符串:userName。依赖IUserProvider可能没有太多附加值。所以我知道我不希望它依赖于HttpContext,而且我确实知道我所需要的只是一个字符串(userName)-我需要看看我是否可以学习足够的StructureMap foo来实现这一点为我连接。 (sirrocoo的答案提示了从哪里开始,但他删除了它:*()。