38

Is there anything wrong with my code here? I keep getting this error:

System.InvalidOperationException: The request message was already sent. Cannot send the same request message multiple times.

My HttpRequestMessage is inside a Func so I figured I get a brand new request each time I pass in func().

public async Task<HttpResponseMessage> GetAsync(HttpRequestMessage request)
{
     return await RequestAsync(() => request);
}

public async Task<HttpResponseMessage> RequestAsync(Func<HttpRequestMessage> func)
{
   var response = await ProcessRequestAsync(func);

    if (response.StatusCode == HttpStatusCode.Unauthorized)   
    {
        WaitForSomeTime();
        response = await ProcessRequestAsync(func);        
    }

    return response;
}

private async Task<HttpResponseMessage> ProcessRequestAsync(Func<HttpRequestMessage> func)
{
    var client = new HttpClient();
    var response = await client.SendAsync(func()).ConfigureAwait(false);
    return response;
}
Prabhu
  • 12,995
  • 33
  • 127
  • 210

2 Answers2

35

You are calling the same func parameter twice:

var response = await ProcessRequestAsync(func);
//...
response = await ProcessRequestAsync(func);

In this case func returns the same request every single time. It doesn't generate a new one every time you call it. If you truly need a different request each time then func needs to return a new message each call:

var response = await GetAsync(() => new HttpRequestMessage()); // Create a real request.

public async Task<HttpResponseMessage> GetAsync(Func<HttpRequestMessage> requestGenerator)
{
     return await RequestAsync(() => requestGenerator());
}
i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • 1
    Thanks @i3arnon. I'll give that a shot and report back. – Prabhu Jul 30 '14 at 21:41
  • Looks like that was it. Question--if I just want to just change the header attribute of the HttpRequestMessage after WaitForSometime(), should recreate the object again, with the new header and assign it back to the same func? – Prabhu Jul 30 '14 at 22:02
  • @Prabhu I actually see no point of using a `func` instead of just passing a simple parameter. Then you can try and just change the header and send again. If that fails you can create a new one with the headers and copy the relevant properties off the old one. – i3arnon Jul 30 '14 at 22:13
  • That's what I was trying to do initially, but when I have content, I ran into this problem: http://stackoverflow.com/questions/25044166/how-to-clone-a-httprequestmessage-when-the-origina-request-has-content?noredirect=1#comment38953745_25044166 – Prabhu Jul 30 '14 at 22:20
  • 1
    @Prabhu I see. Then yes, the second call to func must create a new request instance and just set your headers before sending again. – i3arnon Jul 30 '14 at 22:26
  • 11
    This is especially useful advice if for instance you use Polly to retry your request. If all you do is re-send the *same* request (the reason why I'm here!) then you get that same exception that the OP mentioned. – Larry Smith Jul 10 '19 at 21:02
  • I have tried same approach, but still facing the issue. Can someone help me what needs to be done. – sar Jun 27 '22 at 12:11
7

I had the same issue, but no repetition in my code. Turned out I had added a watch on an asynchronous process. That watch called the process while I stepped through the code, so that when I got to the line I was trying to debug it crashed with this error message. Removing all watches solved the problem. Leaving this here for other people who might have the same problem.

Lavandysh
  • 531
  • 1
  • 7
  • 15