如何在使用HttpServer的测试中使用Formatter?

时间:2014-01-01 22:07:55

标签: asp.net-web-api

在我的Web API应用程序中,我使用HttpServer在单元测试中包含我的控制器,我正在使用HttpClient直接调用它,例如:

[Fact]
public void TestMyController()
{
    var config = new HttpConfiguration();
    config.Routes.MapHttpRoute("default", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });

    var server = new HttpServer(config);
    var client = new HttpClient(server);

    var response = client.GetAsync("http://localhost/api/test/values").Result;
}

我注意到(通过逐步调试,并在其他SO帖子上确认),JsonFormatter并未真正运行 - 它已初始化,但未已行使。由于此测试未打开套接字,并且HttpClient通过HttpServer API直接调用HttpMessageHandler,因此不会运行格式化/序列化,因为它不是需要的。

在我的情况下,我有一些自定义的格式化/序列化/反序列化代码,这些代码在这些测试期间没有被命中,但是当我在真实的Web服务器中运行时,它会受到影响。我想在这些测试中运用该代码;在测试时排除序列化/反序列化代码路径似乎也很危险。对此有何建议?

1 个答案:

答案 0 :(得分:1)

下面是一个快速示例,说明如何强制格式化程序进行序列化/反序列化。我们在此处将ObjectContent转换为StreamContent。在下面的代码中,对CopyToAsync的调用触发了格式化程序被强制序列化的路径。如果是去保护,为了确保我们通过格式化,我们希望内容属于ObjectContent以外的类型,因为ReadAsAsync具有特殊情况ObjectContnent的内部逻辑,我们希望规避它。

HttpClient client = new HttpClient(new InMemoryHttpContentSerializationHandler(new HttpServer(config)));

public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
    public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Content = await ConvertToStreamContentAsync(request.Content);

        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        response.Content = await ConvertToStreamContentAsync(response.Content);

        return response;
    }

    private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
    {
        if (originalContent == null)
        {
            return null;
        }

        StreamContent streamContent = originalContent as StreamContent;

        if (streamContent != null)
        {
            return streamContent;
        }

        MemoryStream ms = new MemoryStream();

        await originalContent.CopyToAsync(ms);

        // Reset the stream position back to 0 as in the previous CopyToAsync() call,
        // a formatter for example, could have made the position to be at the end
        ms.Position = 0;

        streamContent = new StreamContent(ms);

        // copy headers from the original content
        foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
        {
            streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
        }

        return streamContent;
    }
}