user17753
user17753

Reputation: 3161

status code on async webresponse task

I want to hit a plethora (100k+) of JSON files as rapidly as possible, serialize them, and store the HTTP response status code of the request (whether it succeeded or failed). (I am using System.Runtime.Serialization.Json and a DataContract). I intend to do further work with the status code and serialized object, but as a test bed I have this snippet of code:

List<int> ids = new List<int>();
for (int i = MIN; i < MAX; i++)
    ids.Add(i);
var tasks = ids.Select(id =>
{
var request = WebRequest.Create(GetURL(id));
return Task
    .Factory
    .FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, id)
    .ContinueWith(t =>
    {
    HttpStatusCode code = HttpStatusCode.OK;
    Item item = null;
    try
    {
        using (var stream = t.Result.GetResponseStream())
        {
        DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(Item));
        item = ((Item)jsonSerializer.ReadObject(stream));
        }
    }
    catch (AggregateException ex)
    {
        if (ex.InnerException is WebException)
        code = ((HttpWebResponse)((WebException)ex.InnerException).Response).StatusCode;
    }

    });
}).ToArray();
Task.WaitAll(tasks);

Using this approach I was able to process files much more quickly than the synchronous approach I was doing before.

Though, I know that the GetResponseStream() throws the WebException when the status code is 4xx or 5xx. So to capture those status codes I need to catch this exception. However, in the context of this TPL it is nested in an InnerException on an AggregateException. This makes this line really confusing:

    code = ((HttpWebResponse)((WebException)ex.InnerException).Response).StatusCode;

Though, this works... I was wondering if there is a better/clearer way to capture such an exception in this context?

Upvotes: 0

Views: 2532

Answers (2)

Thomas
Thomas

Reputation: 3560

Try this on for size. GetBaseException returns the exception that caused the problem.

try
{
}
catch (System.AggregateException aex)
{

    var baseEx = aex.GetBaseException() as WebException;
    if (baseEx != null)
    {
        var httpWebResp = baseEx.Response as HttpWebResponse;
        if (httpWebResp != null)
        {
            var code = httpWebResp.StatusCode;
            // Handle it...
        }                    
    }

    throw;
}

Upvotes: 1

Nick Hill
Nick Hill

Reputation: 4917

Take a look at MSDN article: Exception Handling (Task Parallel Library)

For example, you might want to rewrite your code as follows:

try
{
    using (var stream = t.Result.GetResponseStream())
    {
        DataContractJsonSerializer jsonSerializer = new
            DataContractJsonSerializer(typeof(Item));

        item = ((Item)jsonSerializer.ReadObject(stream));
    }
}
catch (AggregateException ex)
{
    foreach (var e in ex.InnerExceptions)
    {
        bool isHandled = false;
        if (e is WebException)
        {
            WebException webException = (WebException)e;
            HttpWebResponse response = webException.Response as HttpWebResponse;
            if (response != null)
            {
                code = response.StatusCode;
                isHandled = true;
            }
        }

        if (!isHandled)
            throw;
    }
}

Upvotes: 2

Related Questions