Reputation: 8626
Trying to implement a WebRequest and return to the caller synchronously. I have tried various implementations and I think this would be the most appropriate so far.
Unfortunately the following code throws an InvalidOperationException
with the message
EndGetResponse can only be called once for each asynchronous operation
I really struggled enough to make this happen and its really vital to the library I build to use the WebRequest like this.
The following code is intend to use in Windows Phone 8 and Windows 8 platforms.
I already understand the async/await pattern and used it, but it is REALLY vital for me to use the synchronous version of the web service request in a part of my library.
The code:
public void ExecuteRequest(string url, string requestData)
{
WebRequest request = WebRequest.Create(new Uri(url));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Headers["Header-Key"] = "AKey";
DTOWebRequest webRequestState = new DTOWebRequest
{
Data = requestData,
Request = request
};
ManualResetEventSlim resetEventSlim = new ManualResetEventSlim(false);
// Begin the request using a delegate
request.BeginGetRequestStream(ar =>
{
DTOWebRequest requestDataObj = (DTOWebRequest )ar.AsyncState;
HttpWebRequest requestStream = (HttpWebRequest)requestDataObj.Request;
string data = requestDataObj.Data;
// Convert the string into a byte array.
byte[] postBytes = Encoding.UTF8.GetBytes(data);
try
{
// End the operation
using (Stream endGetRequestStream = requestStream.EndGetRequestStream(ar))
{
// Write to the request stream.
endGetRequestStream.Write(postBytes, 0, postBytes.Length);
}
// Get the response using a delegate
requestStream.BeginGetResponse(result =>
{
DTOWebRequest requestDataObjResult = (DTOWebRequest )ar.AsyncState;
HttpWebRequest requestResult = (HttpWebRequest)requestDataObjResult.Request;
try
{
// End the operation
using (HttpWebResponse response = (HttpWebResponse)requestResult.EndGetResponse(ar)) // Here the exception is thrown.
{
HttpStatusCode rcode = response.StatusCode;
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
// The Response
string responseString = streamRead.ReadToEnd();
if (!string.IsNullOrWhiteSpace(requestDataObjResult.FileName))
{
FileRepository fileRepo = new FileRepository();
fileRepo.Delete(requestDataObjResult.FileName);
}
Debug.WriteLine("Response : {0}", responseString);
}
}
catch (WebException webEx)
{
WebExceptionStatus status = webEx.Status;
WebResponse responseEx = webEx.Response;
Debug.WriteLine(webEx.ToString());
}
resetEventSlim.Set(); // Signal to return handler
}, requestDataObj);
}
catch (WebException webEx)
{
WebExceptionStatus status = webEx.Status;
WebResponse responseEx = webEx.Response;
Debug.WriteLine(webEx.ToString());
}
}, webRequestState);
resetEventSlim.Wait(5000); // Wait either for Set() or a timeout 5 secs.
}
}
Thank you.
Upvotes: 0
Views: 1433
Reputation: 14836
You can't do synchronous web calls in Windows Phone and that's why you aren't.
If you were, you'd be calling GetRequestStream
instead of BeginGetRequestStram
/EndGetRequestStream
.
The only reason to be synchronous on Windows Phone is to block the UI which is a very bad idea.
You should use an HttpClient
and àsync-await` instead.
But if you really think you should (and can) do asynchronous calls on Windows Phone, you can always try something like this:
public void ExecuteRequest(string url, string requestData)
{
try
{
WebRequest request = WebRequest.Create(new Uri(url));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Headers["Header-Key"] = "AKey";
// Convert the string into a byte array.
byte[] postBytes = Encoding.UTF8.GetBytes(requestData);
using (var requestStream = request.EndGetRequestStream(request.BeginGetRequestStream(null, null)))
{
// Write to the request stream.
endGetRequestStream.Write(postBytes, 0, postBytes.Length);
}
using (var response = request.EndGetResponse(request.BeginGetResponse(null, null)))
{
using (var streamRead = new StreamReader(response.GetResponseStream()))
{
// The Response
string responseString = streamRead.ReadToEnd();
if (!string.IsNullOrWhiteSpace(requestDataObjResult.FileName))
{
var fileRepo = new FileRepository();
fileRepo.Delete(request.FileName);
}
Debug.WriteLine("Response : {0}", responseString);
}
}
}
catch (WebException webEx)
{
WebExceptionStatus status = webEx.Status;
WebResponse responseEx = webEx.Response;
Debug.WriteLine(webEx.ToString());
}
}
But I really think you should revise your decision/need.
Upvotes: 1