如何在Web API控制器(MVC 4)中访问HttpServerUtility

时间:2013-02-23 22:28:12

标签: asp.net-mvc-4 asp.net-web-api httpcontext

我需要在MVC 4 ApiController的控制器中访问Server.MapPath(virtualPath)方法。

答案通常是从ControllerContext.HttpContext.Server访问它。但是,与MvcControllers不同,ApiController的ControlerContext没有HttpContext。

在Global.asax.cs中实例化的WebApiAppication具有HttpContext元素(Context)。但是,与MVC 3及更早版本不同,我找不到从控制器访问WebApiApplication的方法。 (早期的代数在静态实例变量中存储了对它的引用.MVC 4删除了它。)

另外,当我从一个单元测试中调用控制器方法时,我正试图找到一些在没有大量额外脚手架的情况下也可以工作的东西。我想我可以使用HttpContext.Current(至少它编译)访问它,即使在WebApi控制器中也是如此,但我无法模拟它进行测试。 (我在这里谈论单元测试,你直接调用Controller方法。我已经看到了一些最近的教程,你用一个瘦的HttpClient进行单元测试,从而测试整个堆栈。这看起来更像是低级集成测试对我来说。)

这似乎不应该那么困难,但我花了几个小时谷歌搜索并尝试了一些事情,而且我的头部因为撞墙而变得血腥。

2 个答案:

答案 0 :(得分:0)

我建议你抽象这个功能:

public interface IMyDependency
{
    string MapPath(string path);
}

然后有一个实现:

public class MyConcreteDependency: IMyDependency
{
    public string MapPath(string path)
    {
        return HostingEnvironment.MapPath(path);
    }
}

最后你的ApiController完全独立于所有静态方法调用,使它对单元测试友好:

public class MyController: ApiController
{
    private readonly IMyDependency dependency;
    public MyController(IMyDependency dependency)
    {
        this.dependency = dependency;
    }

    public HttpResponseMessage Get()
    {
        var path = this.dependency.MapPath("~/App_Data");
        ...
    }
}

答案 1 :(得分:0)

对于ApiControllers,请自己构建一个DelegatingHandler并将所有好处推送到request.Properties。无论您是在测试还是在线运行,您都可以从您的请求中检索它们。这样做的好处是,您可以在Controller中对Session进行零依赖。

的MessageHandler

public class ContextHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        // get the goodies to add onto the request
        var goodies = /* call to goodieGoodieYumYum */


        // add our goodies onto the request
        request.Properties.Add(Constants.RequestKey_Goodies, goodies);

        // pass along to the next handler
        return base.SendAsync(request, cancellationToken);
    }
}

控制器操作

var goodies = (List<Goodie>)Request.Properties[Constants.RequestKey_Goodies];