Initially I want to send a first request without client certificates and if the error is "an authentication error" then I want to resend the request with the certificates attached. So the code first is
HttpStringContent ehttpContent = new HttpStringContent(content);
HttpRequestMessage req2 = new HttpRequestMessage(method, resourceUri);
req2.Headers.Add("SOAPAction", soapAction);
req2.Content = ehttpContent;
req2.Content.Headers.ContentType = HttpMediaTypeHeaderValue.Parse("text/xml; charset=utf-8");
bool retry= await FirstLoginAttempt(...);
if( retry) {
newHttpClient = new HttpClient(baseFilter2);
try
{
cts.CancelAfter(Constants.HttpTimeOut);
System.Diagnostics.Debug.WriteLine(ehttpContent);
eresponse = await newHttpClient.SendRequestAsync(req2).AsTask(cts.Token);
if (cts != null)
{
cts.Dispose();
cts = null;
} catch { ... }
}
the previous code calls FirstLoginAttempt that it might fail with a certificate error. It returns true or false and then the previous code tries to send a new httpClient with certificates.
public static async Task<bool> FirstLoginAttempt() {
httpClient = new HttpClient();
try
{
cts.CancelAfter(Constants.HttpTimeOut);
var operation = httpClient.SendRequestAsync(ereq).AsTask(cts.Token);
eresponse = await operation;
if (cts != null) { cts.Dispose(); cts = null; }
}
catch (TaskCanceledException e)
{
if (cts != null) { cts.Dispose(); cts = null; }
throw e;
}
catch (Exception exx)
{ ... }
}
When the first login attempt returns true in order to try again the second httpclient (that has the same contect) fails and the exception says that I cannot send the same request twice. that probably means that the previous operation is not finished? How can I resolve my problem? Can I somehow get sure that the first request lifecycle is over in order to retry?
My environment is Windows Phone 8.1
Update #1. After using lambda
StackTrace = " at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n ... Message = "Exception from HRESULT: 0x80072EFD" (Throw for non success)
above the stack trace ... ...
Func<HttpRequestMessage> httpRequestCreator = () =>
{
HttpStringContent ehttpContent = new HttpStringContent(content);
var req = new HttpRequestMessage(method, resourceUri)
{
Content = ehttpContent
};
req.Headers.Add("SOAPAction", soapAction);
req.Content.Headers.ContentType = HttpMediaTypeHeaderValue.Parse("text/xml; charset=utf-8");
return req;
};
if (cts != null) { cts.Dispose(); cts = null; }
cts = new System.Threading.CancellationTokenSource();
newHttpClient = new HttpClient();
try
{
cts.CancelAfter(Constants.HttpTimeOut);
eresponse = await newHttpClient.SendRequestAsync(httpRequestCreator()).AsTask(cts.Token);
if (cts != null) { cts.Dispose(); cts = null; }
}
catch (TaskCanceledException e
{
if (cts != null) { cts.Dispose(); cts = null; }
throw e;
}
catch (Exception exx)
{
exception2 = exx;
...
...
}
The problem is in the fact you're re-using your HttpRequestMessage
for both requests, which you can't do. Instead, create a new request for each message you want to send. One way to deal with this is create a Func<HttpRequestMessage>
which returns a fresh instance each time:
Func<HttpRequestMessage> httpRequestCreator = () =>
{
var request = new HttpRequestMessage(method, resourceUri)
{
Content = content
};
request.Headers.Add("SOAPAction", soapAction);
request.Content.Headers.ContentType =
HttpMediaTypeHeaderValue.Parse("text/xml; charset=utf-8");
return request;
};
bool retry = await FirstLoginAttempt(httpRequestCreator());
// If re-try is needed:
var operation = await httpClient.SendRequestAsync(httpRequestCreator()).AsTask(cts.Token);
As a side note - Don't relay on exception handling for normal code execution paths. Instead, consider sending the authentication information even if it might not be needed, or rather request that the service you're querying provide information at run-time regarding if you need to pass that information along.
User contributions licensed under CC BY-SA 3.0