[当前,我有一个ActionFilter,它从HttpContext获取当前用户名,并将其传递给在服务方法上使用它的操作。例如:
Service.DoSomething(userName);
我现在有理由不在操作级别而是在控制器构造函数级别执行此操作。目前,我正在使用结构图来创建控制器并注入服务。我在看类似的东西:
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。
具有接口摘要HttpContext.Current
。仅公开您需要的方法。例如,在实现中,GetUserName()
将调用HttpContext.Current.User.Identity.Name
。使它尽可能薄。
采用该抽象并将其注入到其他提供程序类中。这将允许您通过模拟http上下文抽象来测试提供程序。作为附带的好处,除了模拟它之外,您还可以使用HttpContext
抽象来做其他漂亮的事情。重用它,一方面。向袋等添加通用类型参数。
听起来您应该使用HttpContextBase
而不是HttpContextUserProvider
。这是HttpContext
的现成的抽象,允许您创建一个模拟程序,编写UnitTests并注入您的依赖项。
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));
我不确定你为什么要打扰。似乎仅在HttpContextUserProvider中直接使用HttpContext.Current是正确的事情。您将永远不会替换为其他HttpContext ...
[也许我遗漏了一些东西,但是上面的答案对我不起作用(自从被删除以来,它仍然是一个有用的答案,它显示了如何告诉SM传递构造函数参数)。相反,如果我这样做:
ObjectFactory.Initialize(x =>
{
x.BuildInstancesOf<HttpContext>()
.TheDefault.Is.ConstructedBy(() => HttpContext.Current);
x.ForRequestedType<IUserProvider>()
.TheDefault.Is.OfConcreteType<HttpContextUserProvider>();
});
我明白了。我在找到以下内容后进行了此操作:If you need something in StructureMap, but you can’t build it with new()…]
编辑:
由于Brad的回答,我认为
我对HttpContext
有更好的处理。他的回答肯定有效,我只是不确定我是否喜欢在类中调用HttpContext.Current
(似乎它隐藏了依赖关系,但我在这方面还不是专家)。据我所知,以上代码应适用于注入HttpContext
。 Matt Hinze提出了一个补充点,即如果HttpContext
我需要的只是User.Identity.Name
,则我的设计应该是明确的(HttpContext
周围的接口仅显示我的需求)。我认为这是个好主意。
事情是在午餐时,我有点意识到我的服务确实只需要依赖字符串:userName
。依靠IUserProvider
可能没有太多附加值。所以我知道我不希望它依赖于HttpContext
,而且我确实知道我所需要的只是一个字符串(userName
)-我需要看看我是否可以学习足够的StructureMap
foo来完成此操作对我而言。 (sirrocoo的回答提示了从哪里开始,但他删除了它:*()。