【问题标题】:HttpRequestMessage Content Disposition null when unit testing单元测试时 HttpRequestMessage Content Disposition null
【发布时间】:2017-05-19 15:17:35
【问题描述】:

我正在尝试为自定义 MultipartMemoryStreamProvider 编写测试 - 一个与 MultipartFormDataMemoryStreamProvider.cs 非常相似的测试

特别是,我正在尝试测试我自己的GetStream(HttpContent parent, HttpContentHeaders headers) 方法的实现。

它需要一个 HttpContent 和 HttpContentHeaders。

为了实现这一点,我尝试创建一个控制器上下文和控制器,然后从该控制器请求中传递适当的属性。

事实上,我已经尝试实现这个(重复)问题的答案:Testing a Web API method that uses HttpContext.Current.Request.Files?

我尝试的所有结果都导致标题上的Content-Dispositionnull,如下图所示:

知道我错过了什么吗?

为了代码,这里是代码的副本。您会注意到它与另一个问题的答案相同。我就是无法通过 null content-disposition。

  var content = new ByteArrayContent(new Byte[100]);
        content.Headers.Add("Content-Disposition", "form-data");
        var controllerContext = new HttpControllerContext
        {
            Request = new HttpRequestMessage
            {
                Content = new MultipartContent { content }
            }
        };
        var controller = new MockController();
        controller.ControllerContext = controllerContext;

MockController 很简单:

public class MockController : ApiController { }

【问题讨论】:

  • 为什么您希望Content-DispositionMultipartContent 上可用,而您在ByteArrayContent 上设置它?
  • 显然是因为我很愚蠢,哈哈——我觉得我已经尝试过了,这就是导致我发现另一个答案说把它放在ByteArrayContent 上的原因——不知道我怎么弄错了第一位,虽然现在可以了。谢谢! :)
  • 很高兴它有帮助:)。如果您无论如何都开始奖金,我想我会创建一个答案。
  • 当然,去吧:)

标签: c# unit-testing


【解决方案1】:

如果您希望 Content-Disposition 标头出现在 MultipartContent 中,则应设置为 MultipartContent 而不是 ByteArrayContent

但如果你想模拟从网页上传文件,你需要在ByteArrayContent 上设置Content-Disposition 标头。在这种情况下,要查看 Content-Disposition 的值,您需要遍历 MultipartContent 的内部内容:

var multipart = await Request.Content.ReadAsMultipartAsync();
foreach (var content in result.Contents)
{
     var contentDisposition = content.Headers.ContentDisposition;
}

您可以查看本教程:Sending HTML Form Data in ASP.NET Web API。它可能有点过时,但它显示了这个想法。

编辑:刚刚检查过,它似乎与您在问题中引用的答案中提到的教程相同。

【讨论】:

    【解决方案2】:

    如果我错了,请纠正我。以下是我对情况的分析:

    MultipartContent 类基本上有一个子HttpContent 对象的集合(ByteArrayContent 继承自HttpContent)。它覆盖WriteNextContentHeadersAsync 方法并从其子HttpContent 集合中写出标题。它确实有自己的Headers 属性,但它继承自HttpContent,没有覆盖,没什么特别的。

    因此,您尝试做的事情基本上不是以这种方式实现的。 MultipartContent 确实将标头写入输出,但不会在其自己的 Headers 集合中反映这些标头。

    您可以覆盖此行为。简单而幼稚的实现可能如下:

    public class MyMultipartContent : MultipartContent
    {
        public override void Add(HttpContent content)
        {
            base.Add(content);
            foreach (var header in content.Headers.ToList())
            {
                if (!this.Headers.Contains(header.Key))
                    this.Headers.Add(header.Key, header.Value);
            }
        }
    }
    

    因此,来自子 HttpContent 的每个标题都将添加到 MultipartContent's Header 集合中。也许这是完全错误的,会导致错误和其他问题:)

    另一种选择是枚举MultipartContent 中的子HttpContent 对象:

    foreach (var httpContent in (MultipartContent) controller.Request.Content)
    {
        var header = httpContent.Headers.ContentDisposition; // here it is
    }
    

    另一种选择是使用扩展方法:

    public static class MyExtensions
    {
        public static ContentDispositionHeaderValue MyGetContentDisposition(this HttpContent httpContent)
        {
            if (httpContent is MultipartContent)
                return ((MultipartContent) httpContent).FirstOrDefault(c => c.Headers.ContentDisposition != null)?.Headers.ContentDisposition;
            return httpContent.Headers.ContentDisposition;
        }
    }
    

    如果httpContentMultipartContent,则从它的子HttpContent 集合返回第一个不为空的ContentDisposition 标头。

    var hereItIs = controller.Request.Content.MyGetContentDisposition();
    

    【讨论】:

      猜你喜欢
      • 2018-09-04
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-23
      • 2012-02-27
      相关资源
      最近更新 更多