asp.net-mvc – 如何在Action中获取和设置http标头,这是一种可测试的方式

我有一个返回FileContentResult或NotModifiedResult的操作,它是一个自定义结果类型,它返回HTTP 304以指示所请求的资源尚未被修改,如下所示:

[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
    var item = Service.GetItem(id);

    var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
    var tag = Convert.ToBase64String(item.Version.ToArray());

    if (tag == requestTag)
    {
        return new NotModifiedResult();
    }

    if (item.Thumbnail != null)
    {
        var thumbnail = item.Thumbnail.ToArray();
        var mime = item.PictureMime;

        Response.AppendHeader("ETag", tag);

        return File(thumbnail, mime);
    }
    else
    {
        return null;
    }
}

此操作需要访问Response对象,该对象在测试期间当然不存在,因此使此操作不可测试.我可以在它周围添加条件语句,以便它在测试期间运行,但是我无法测试正确设置的标头.

这个问题的解决方案是什么?

仅供参考,ReplaceMissingPicture过滤器返回一个特定的资源,以防从此操作返回null,以便出于同样的原因将MapPath()调用从控制器中移出.

最佳答案 第一步是创建一个简化所需服务的界面: –

  public interface IHeaders
  {
       public string GetRequestHeader(string headerName);
       public void AppendResponseHeader(string headerName, string headerValue);
  }

现在创建一个默认实现: –

 public Headers : IHeaders
 {
       public string GetRequestHeader(string headerName)
       {
            return HttpContext.Current.Request[headerName];
       }
       public void AppendResponseHeader(string headerName, string headerValue)
       {
            HttpContext.Current.Response.AppendHeader(headerName, headerValue);
       } 
 }

现在为您的Controller添加一个新字段: –

     private IHeaders myHeadersService;

向控制器添加新的构造函数: –

     public MyController(IHeaders headersService) 
     {
         myHeadersService = headersService;
     }

修改或添加默认构造函数: –

    public MyController()
    {
         myHeadersService = new Headers();
    }

现在在您的Action代码中使用myHeadersService而不是Response和Request对象.

在您的测试中,创建您自己的IHeaders接口实现,以模拟/测试Action代码,并在构造Controller时传递该实现.

点赞