HttpRequestMessage内容在单元测试时处置为null

时间:2017-05-19 15:17:35

标签: c# unit-testing

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

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

它需要一个HttpContent和HttpContentHeaders。

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

事实上,我已尝试在此(重复)问题上实施答案:Testing a Web API method that uses HttpContext.Current.Request.Files?

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

enter image description here

enter image description here

知道我缺少什么吗?

为了代码,这里是代码的副本。您会注意到它与另一个问题的答案中的相同。我只是无法通过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 { }

2 个答案:

答案 0 :(得分:2)

如果您希望Content-Disposition标题出现在MultipartContent中,则应该在MultipartContent而不是ByteArrayContent上进行设置。

但是,如果您想通过网页模拟文件上传,则需要在Content-Disposition上设置ByteArrayContent标题。在这种情况下,要查看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。它可能有点过时,但它显示了这个想法。

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

答案 1 :(得分:0)

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

班级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集合中。也许这是完全错误的,会导致错误和其他问题:)

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

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,则会从其子ContentDisposition集合中返回第一个非空HttpContent标题。

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