【问题标题】:How do access the HttpServerUtility in a WebAPI controller (MVC 4)如何在 Web API 控制器中访问 HttpServerUtility (MVC 4)
【发布时间】:2013-02-23 22:28:11
【问题描述】:

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

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

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

另外,当我从单元测试中调用控制器方法时,我正在尝试找到一些无需大量额外脚手架也可以工作的东西。我想我可以访问它,即使在 WebApi 控制器中,使用 HttpContext.Current (至少它编译),但我不能模拟它进行测试。 (我在这里说的是单元测试,您可以直接调用 Controller 方法。我看过一些最近的教程,您可以使用瘦 HttpClient 进行单元测试,从而测试整个堆栈。这似乎更像是低级集成测试对我来说。)

这似乎不应该那么困难,但我已经花了几个小时在谷歌上搜索它并尝试了一些东西,我的头因为撞到墙上而变得血腥。

【问题讨论】:

  • 可能的解决方案是您可以将ControllerContext.HttpContext.Server 包装到另一个类进行测试,为什么不呢?

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


【解决方案1】:

我建议你抽象一下这个功能:

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");
        ...
    }
}

【讨论】:

    【解决方案2】:

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

    消息处理程序

    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];
    

    【讨论】:

      猜你喜欢
      • 2014-06-01
      • 2016-07-15
      • 2019-05-26
      • 2019-01-06
      • 1970-01-01
      • 2012-09-04
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      相关资源
      最近更新 更多