Question

My objective is to retry an asynchronous HttpWebRequest when it fails.

When I Abort() an HttpWebRequest, I cannot BeginGetResponse() again. So the only way to request again probably is recreate the HttpWebRequest object. It seems to require a lot of work since I would have to copy all properties from the old object. Is there any shortcut?

Note: I think that serialization it would solve my problem, but this class won't serialize, as discussed in a previous question.

Update Removed example source code because it was unnecessary

Current view on this matter There is no shortcut, the only way to redo the request is creating another HttpWebRequest object the same way you created the original one.

Was it helpful?

Solution

It's possible!

You just need to create a new HttpWebRequest and copy all of the properties over to it from the old object via reflection.

Here's an extension method that does this:

/// <summary>
/// Clones a HttpWebRequest for retrying a failed HTTP request.
/// </summary>
/// <param name="original"></param>
/// <returns></returns>
public static HttpWebRequest Clone(this HttpWebRequest original)
{
    // Create a new web request object
    HttpWebRequest clone = (HttpWebRequest)WebRequest.Create(original.RequestUri.AbsoluteUri);

    // Get original fields
    PropertyInfo[] properties = original.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

    // There are some properties that we can't set manually for the new object, for various reasons
    List<string> excludedProperties = new List<String>(){ "ContentLength", "Headers" };

    // Traverse properties in HttpWebRequest class
    foreach (PropertyInfo property in properties)
    {
        // Make sure it's not an excluded property
        if (!excludedProperties.Contains(property.Name))
        {
            // Get original field value
            object value = property.GetValue(original);

            // Copy the value to the new cloned object
            if (property.CanWrite)
            {
                property.SetValue(clone, value);
            }
        }
    }

    return clone;
}

When you want to re-issue the same request, simply execute the following:

// Create a request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://www.google.com/");

// Change some properties...

// Execute it
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

// Clone the request to reissue it using our extension method
request = request.Clone();

// Execute it again
response = (HttpWebResponse)request.GetResponse();

OTHER TIPS

It's not possible.

An HTTPWebRequest instance represents literally one request instance (although there are edge cases where it will retry internally), and is therefore not something which can logically be repeated. It is capable of returning exactly one response (request/response being a logical pair), and although you can inspect that response multiple times you'll get exactly the same object.

Basically, you're thinking an HTTPWebRequest instance is a sort of factory, but it's really concrete. You have to create another instance.

Where are you trying to serialize the request? It might be a good idea to serialize the request before you try to make it, and then resend the request on failure (from the serialized instance).

Also, you might want to remove the proxy, serialize the instance, and then set the proxy back, since that seems to be where the problem lies in serializing the request.

There is no shortcut, the only way to redo the request is creating another HttpWebRequest object the same way you created the original one.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top