Why can't I catch exception from HttpClient SendAsync when using ObjectContent

允我心安 提交于 2019-12-12 10:42:19

问题


I can't seem to catch certain exceptions thrown from the System.Net.Http.HttpClient's SendAsync method. Specifically, the ProtocolViolationException, thrown from the HttpWebRequest.ChechProtocol method. The code seems to deadlock or hang, and the catch is never entered.

I've created an NUnit unit test to illustrate the issue clearly.

public class TestClass
{
    public bool TestProperty { get; set; }
}

[Test]
public async Task CanCatchExceptionFromHttpClientSendAsync()
{
    var caughtException = false;

    try
    {
        var request = new HttpRequestMessage(HttpMethod.Get, "http://somedomain.com")
        {
            Content = new ObjectContent<TestClass>(
                new TestClass { TestProperty = true },
                new JsonMediaTypeFormatter())
        };

        await new HttpClient().SendAsync(request);
    }
    catch (Exception)
    {
        caughtException = true;
    }

    Assert.IsTrue(caughtException);
}

using StringContent instead of ObjectContent the test passes. Am I missing something simple?

Update

Based on the fact that StringContent allows the exception to be caught, and ObjectContent deadlocks, I've been able to deduce that this is somehow related to the MediaTypeFormatter's WriteToStreamAsync method.

I've managed to work around the problem by "pre-formatting" the content in to a ByteArrayContent like so:

private static async Task<HttpContent> CreateContent<T>(
    T value,
    string mediaType, 
    MediaTypeFormatter formatter)
{
    var type = typeof(T);
    var header = new MediaTypeHeaderValue(mediaType);

    HttpContent content;
    using (var stream = new MemoryStream())
    {
        await formatter.WriteToStreamAsync(type, value, stream, null, null);

        content = new ByteArrayContent(stream.ToArray());
    }

    formatter.SetDefaultContentHeaders(type, content.Headers, header);

    return content;
}

and then consuming it like this:

var content = await CreateContent(
    new TestClass(), 
    "application/json", 
    new JsonMediaTypeFormatter());

var request = new HttpRequestMessage(HttpMethod.Get, "http://foo.com")
{
    Content = content
};

That at least allows the catch to work properly, but I


回答1:


This is a known bug in HttpClient. You can workaround it by buffering yourself, setting content-length (as ByteArrayContent does) or using chunked transfer encoding (if supported on your platform, not supported on Phone).



来源:https://stackoverflow.com/questions/23547814/why-cant-i-catch-exception-from-httpclient-sendasync-when-using-objectcontent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!