Call asynchronous external web service in asp.net MVC controller - c#

In the Asp.net MVC controller (GET method) I am calling external web service - for geolocation of IP - returning json data for IP location. How can I make the call to be async, hence the stack can continue while waiting the response from the service. When the GEO IP request finished I want to be able to make update to the db. Here is the current sync code:
public ActionResult SelectFacility(int franchiseId, Guid? coachLoggingTimeStampId)
{
//...
string responseFromServer = Helpers.GetLocationByIPAddress(userIpAddress);
HomeModels.GeoLocationModel myojb = new HomeModels.GeoLocationModel();
if (!String.IsNullOrEmpty(responseFromServer))
{
JavaScriptSerializer js = new JavaScriptSerializer();
myojb = (HomeModels.GeoLocationModel)js.Deserialize(responseFromServer, typeof(HomeModels.GeoLocationModel));
}
//...
}
public static string GetLocationByIPAddress(string ipAddress)
{
Stream resStream = null;
string responseFromServer = "";
try
{
string url = GeoLocationPath.FreeGeoIP + ipAddress;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
resStream = response.GetResponseStream();
StreamReader reader = new StreamReader(resStream);
responseFromServer = reader.ReadToEnd();
return responseFromServer;
}
catch (Exception ex)
{
//TODO handle this
}
finally
{
if (null != resStream)
{
resStream.Flush();
resStream.Close();
}
}
return responseFromServer;
}
Any suggestion - Thread, AsyncTask ?
Thanks

Make your ASP.NET MVC controller asynchronous:
http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
Then use HttpClient.GetStringAsync and await its result:
public async Task<ActionResult> SelectFacility(
int franchiseId, Guid? coachLoggingTimeStampId)
{
//...
string responseFromServer = await Helpers.GetLocationByIPAddressAsync(
userIpAddress);
//...
}
public static async Task<string> GetLocationByIPAddress(string ipAddress)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(
GeoLocationPath.FreeGeoIP + ipAddress);
}

Related

HttpWebResponse hangs/freezes when running in a WebAPI

I am using a C# WebAPI project which would call an external API based on its URL. However, when I am trying to retrieve the data back, it hangs/freezes.
The code where it stops is:
var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
I don't understand why it is stopping though. Could it be interfering with the API request I am also making? When I run this code as part of a unit test, I would get a response back within seconds. I don't think it is the API service itself, I think it is my code. I have already tried various API URLS. None of them work.
My full code is:
public static async Task<string> CallWebAPi<T>(string url)
{
string returnValue;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
Stream stream = response.GetResponseStream();
StreamReader strReader = new StreamReader(stream);
returnValue = await strReader.ReadToEndAsync();
return returnValue;
}
Any help would be appreciated.
Possible deadlock ConfigureAwait(false), here are a good explanation from Stephen on what cause deadlocks.
var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null).ConfigureAwait(false);
As a workaround you can use the synchronous functions, create a Task and await this task:
var response = await Task.Run(() =>
{
return (HttpWebResponse)request.GetResponse();
});
This is how i do my Request. Each Part is in an own Function. Its create the Request and you can get the Response synchronous.
public HttpWebRequest CreateRequest(string Url, string Method, string ContentType, object Content, List<RequestHeader> headers)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.Method = Method;
if (!string.IsNullOrWhiteSpace(ContentType)) request.ContentType = ContentType;
else if(Content != null) request.ContentType = "application/json";
if (Content != null)
{
var postData = Newtonsoft.Json.JsonConvert.SerializeObject(Content);
var data = Encoding.ASCII.GetBytes(postData);
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
}
foreach(RequestHeader header in Headers)
{
request.Headers.Add(header.Type, header.Value);
} //class at the end.
return request;
}
public string GetResponse(HttpWebRequest request)
{
var retval = "";
try
{
var response = (HttpWebResponse)request.GetResponse();
retval = ReadResponse(response);
response.Close();
}
catch (Exception ex)
{
resolveException(ex.Message);
}
return retval;
}
public string ReadResponse(HttpWebResponse response)
{
var retval = "";
try
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var responseText = reader.ReadToEnd();
retval = responseText;
}
}
catch (Exception ex)
{
resolveException(ex.Message);
}
return retval;
}
public class RequestHeader
{
public HttpRequestHeader Type { get; set; }
public string Value { get; set; }
}
you dont need Task.Factory.FromAsync. HttpWebRequest already supports asynchronous operations.
You have defined a generic method CalWebApi<T> but have never used a generic type
if your operation is async, use this.
public async Task<T> CalWebApiAsync<T>(string url)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
using (var response = await request.GetResponseAsync())
{
using (var responseStream = response.GetResponseStream())
{
using (var streamReader = new StreamReader(responseStream))
{
var stringResult = await streamReader.ReadToEndAsync();
T objectResult = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(stringResult);
return objectResult;
}
}
}
}
var result = await CallWebApiAsync<YourType>("exteranlapiurl");
if your operation is not async, use this..
public T CalWebApi<T>(string url)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var streamReader = new StreamReader(responseStream))
{
var stringResult = streamReader.ReadToEnd();
T objectResult = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(stringResult);
return objectResult;
}
}
}
}
var result = CallWebApi<YourType>("exteranlapiurl");

Http Web Request Errors in UWP Application

I am using the Microsoft Translator API in .NET UWP application and I'm following the steps for obtaining an access token from the link:
https://msdn.microsoft.com/en-us/library/hh454950.aspx?f=255&MSPPError=-2147217396
I copied the code into my project, but I'm getting errors on the HttpWebRequest GetRequestStream() and GetResponse() methods saying it does not contain a definition for those. I believe the issue is that I'm using a UWP application since I tried it out in a console application and it worked.
Does anyone know how I can get this code to work in my UWP application? TIA.
private AdmAccessToken HttpPost(string DatamarketAccessUri, string requestDetails)
{
//Prepare OAuth request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(DatamarketAccessUri);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(requestDetails);
//webRequest.ContentLength = bytes.Length;
using (Stream outputStream = webRequest.GetRequestStream())
{
outputStream.Write(bytes, 0, bytes.Length);
}
using (WebResponse webResponse = webRequest.GetResponse())
{
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(AdmAccessToken));
//Get deserialized object from JSON stream
AdmAccessToken token = (AdmAccessToken)serializer.ReadObject(webResponse.GetResponseStream());
return token;
}
}
UPDATE
The errors that I was getting for the above code were fixed when I followed the checked answer. However, there's still one more error that I'm trying to fix - I followed the response in the comments below, and while the errors went away, the code exits at the line
WebResponse response = await translationWebRequest.GetResponseAsync();
Relevant code posted below:
//Exits on the WebResponse line
private static async System.Threading.Tasks.Task<string> DetectMethod(string authToken, AdmAccessToken token, string txtToTranslate)
{
string headerValue = "Bearer " + token.access_token;
string uri = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + WebUtility.UrlEncode(txtToTranslate) + "&from=en&to=es";
WebRequest translationWebRequest = WebRequest.Create(uri);
translationWebRequest.Headers["Authorization"] = headerValue;
WebResponse response = await translationWebRequest.GetResponseAsync(); //where it's exiting
System.IO.Stream stream = response.GetResponseStream();
System.Text.Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
System.IO.StreamReader translatedStream = new System.IO.StreamReader(stream, encode);
System.Xml.XmlDocument xTranslation = new System.Xml.XmlDocument();
xTranslation.LoadXml(translatedStream.ReadToEnd());
translatedText = xTranslation.InnerText;
return null;
}
//Where DetectMethod is called from
public static async System.Threading.Tasks.Task<string> Translate(string TextToTranslate)
{
AdmAccessToken admToken;
string headerValue;
AdmAuthentication admAuth = new AdmAuthentication("<>", "<>");//codes removed
try
{
admToken = admAuth.GetAccessToken();
// Create a header with the access_token property of the returned token
headerValue = "Bearer " + admToken.access_token;
await DetectMethod(headerValue, admToken, TextToTranslate); //calls previous method
}
catch (WebException e)
{
ProcessWebException(e);
}
return translatedText;
}
The method that calls upon Translate() method also has await for calling the method and async in its signature. Again, with these changes, there are no more errors, but the program exits at the WebResponse line.
I copied the code into my project, but I'm getting errors on the HttpWebRequest GetRequestStream() and GetResponse() methods saying it does not contain a definition for those. I believe the issue is that I'm using a UWP application since I tried it out in a console application and it worked.
Yes,UWP is targeting .Net Core while console application is targeting normal .Net Framework.
Instead of GetRequestStream and GetResponse you can use the async version like below:
//mark the method as async
private async System.Threading.Tasks.Task<AdmAccessToken> HttpPost(string DatamarketAccessUri, string requestDetails)
{
...
//use 'GetRequestStreamAsync'
using (Stream outputStream =await webRequest.GetRequestStreamAsync())
{
...
}
//use 'GetResponseAsync' instead
using (WebResponse webResponse = await webRequest.GetResponseAsync())
{
...
return token;
}
}
Update: I made a demo using translator API. Here are the codes:
MainPage.xaml:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel VerticalAlignment="Center">
<Button Name="myBtn" Click="myBtn_Click">Click Me</Button>
<TextBlock Name="myTB"></TextBlock>
</StackPanel>
</Grid>
MainPage.xaml.cs:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void myBtn_Click(object sender, RoutedEventArgs e)
{
var translatedText = await Translate("Text for test");
myTB.Text = translatedText;
}
//Exits on the WebResponse line
private static async System.Threading.Tasks.Task<string> DetectMethod(string authToken, AdmAccessToken token, string txtToTranslate)
{
string headerValue = "Bearer " + token.access_token;
string uri = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + WebUtility.UrlEncode(txtToTranslate) + "&from=en&to=es";
WebRequest translationWebRequest = WebRequest.Create(uri);
translationWebRequest.Headers["Authorization"] = headerValue;
WebResponse response = await translationWebRequest.GetResponseAsync(); //where it's exiting
System.IO.Stream stream = response.GetResponseStream();
System.Text.Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
System.IO.StreamReader translatedStream = new System.IO.StreamReader(stream, encode);
System.Xml.XmlDocument xTranslation = new System.Xml.XmlDocument();
xTranslation.LoadXml(translatedStream.ReadToEnd());
//translatedText = xTranslation.InnerText;
return xTranslation.InnerText;
}
//Where DetectMethod is called from
public static async System.Threading.Tasks.Task<string> Translate(string TextToTranslate)
{
AdmAccessToken admToken;
string headerValue;
string translatedText=null;
AdmAuthentication admAuth = new AdmAuthentication("<>", "<>");//codes removed
try
{
admToken =await admAuth.GetAccessToken();
// Create a header with the access_token property of the returned token
headerValue = "Bearer " + admToken.access_token;
translatedText= await DetectMethod(headerValue, admToken, TextToTranslate); //calls previous method
}
catch (WebException e)
{
}
return translatedText;
}
public class AdmAccessToken
{
public string access_token { get; set; }
public string token_type { get; set; }
public string expires_in { get; set; }
public string scope { get; set; }
}
public class AdmAuthentication
{
string clientID = "winffee_4960";
string clientSecret = "N0aTQ4OUKKP5lpNIBs0h9wfFXGpHlel1BpIkmDd1cVE=";
String strTranslatorAccessURI = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13";
String strRequestDetails;
public AdmAuthentication(String str1, String str2)
{
strRequestDetails= string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=http://api.microsofttranslator.com", WebUtility.UrlEncode(clientID), WebUtility.UrlEncode(clientSecret));
}
public async Task<AdmAccessToken> GetAccessToken()
{
WebRequest webRequest = System.Net.WebRequest.Create(strTranslatorAccessURI);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(strRequestDetails);
//webRequest.ContentType = bytes.Length;
using (Stream outputStream = await webRequest.GetRequestStreamAsync())
{
outputStream.Write(bytes, 0, bytes.Length);
}
WebResponse webResponse = await webRequest.GetResponseAsync();
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(AdmAccessToken));
//Get deserialized object from JSON stream
AdmAccessToken token = (AdmAccessToken)serializer.ReadObject(webResponse.GetResponseStream());
string headerValue = "Bearer " + token.access_token;
return token;
}
}
}

Premature end of data while reading from WebResponse class

I am developing a Windows Store App using C# and I am very new at this platform (I have been primarily working on IOS and Android).
I have a simple Async method to download raw data from a remote server. It works ok except that I keep seeing random incomplete reads from the WebResponse class. It is pretty simple method and I cant figure out why it would end prematurely. The remote server is working fine ( ios/web/android fine and are retrieving data) so I am obviously doing something wrong here.
Any help will be great in figuring out this problem.
public async Task<byte[]> doGETRequestAsync(String url)
{
callSuccess = false;
byte[] responseFromServer = null;
try
{
WebRequest request = WebRequest.Create(url);
request.Method = "GET";
WebResponse response = await request.GetResponseAsync();
using (Stream dataStream = response.GetResponseStream())
{
responseFromServer = new byte[response.ContentLength];
int readCount = await dataStream.ReadAsync(responseFromServer, 0, (int)response.ContentLength);
if (readCount != response.ContentLength)
throw new IOException("Premature end of data. Expected: " + response.ContentLength + " received: " + readCount);
}
response.Dispose();
}
catch (HttpRequestException hre)
{
Debug.WriteLine("Exception performing network call : " + hre.ToString());
}
catch (Exception e)
{
Debug.WriteLine("Exception performing network call : " + e.ToString());
}
return responseFromServer;
}
I switched to using HttpClient and HttpClientHandler and it works perfectly. This also supports storing cookies and reusing that on every call.
Here is the code that can handle both GET and POST and return the data as an array of bytes[]. If the response is a utf8 encoded string, then the bytes can be converted to string using System.Text.Encoding.UTF8.GetString(respBytes, 0, respBytes.Length);
Hope it is helpful
class Network
{
static CookieContainer cookieJar = new CookieContainer();
List<KeyValuePair<string, string>> postParameters = new List<KeyValuePair<string, string>>();
// Add post parameter before calling NetworkRequestAsync for POST calls.
public void addPostParameter(String key, String value)
{
postParameters.Add(new KeyValuePair<string, string>(key, value));
}
public async Task<byte[]> NetworkRequestAsync(String url, bool GET_REQUEST)
{
callSuccess = false;
byte[] respBytes = null;
try
{
HttpClientHandler handler = new HttpClientHandler()
{
// Use and reuse cookies in the cookiejar
CookieContainer = cookieJar
};
handler.AllowAutoRedirect = false;
handler.UseCookies = true;
HttpClient client = new HttpClient(handler as HttpMessageHandler)
{
BaseAddress = new Uri(#url)
};
HttpResponseMessage response = null;
if (GET_REQUEST)
{
response = await client.GetAsync(client.BaseAddress);
}
else
{
HttpContent content = new FormUrlEncodedContent(postParameters);
//String postparam=await content.ReadAsStringAsync();
//Debug.WriteLine("Post Param1=" + postparam);
response = await client.PostAsync(client.BaseAddress, content);
callSuccess = true;
}
respBytes = await response.Content.ReadAsByteArrayAsync();
}
catch (Exception e)
{
Debug.WriteLine("Exception performing network call : " + e.ToString());
}
return respBytes;
}
}

Converting ordinary Http Post web request with Async and Await

How I can convert my traditional HttpWebRequest "POST" call with Async / Await pattern, Here with this I am attaching my current code, Any one please help me to convert this code using Async / Await pattern for windows phone 8.
public void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
request.BeginGetRequestStream(GetRequestStreamCallback, new object[] { request, requestBody });
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)((object[])asynchronousResult.AsyncState)[0];
using (var postStream = request.EndGetRequestStream(asynchronousResult))
{
var byteArray = (byte[])((object[])asynchronousResult.AsyncState)[1];
// Write to the request stream.
postStream.Write(byteArray, 0, byteArray.Length);
}
request.BeginGetResponse(GetResponseCallback, request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)asynchronousResult.AsyncState;
try
{
var response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
string responseString = reader.ReadToEnd();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Since Windows Phone 8 doesn't seem to offer the TAP methods you need such as GetRequestStreamAsync the first thing to do is write a little wrapper to provide them for yourself:
public static class WebRequestAsyncExtensions
{
public static Task<Stream> GetRequestStreamAsync(this WebRequest request)
{
return Task.Factory.FromAsync<Stream>(
request.BeginGetRequestStream, request.EndGetRequestStream, null);
}
public static Task<WebResponse> GetResponseAsync(this WebRequest request)
{
return Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse, request.EndGetResponse, null);
}
}
Note the use of Task.Factory.FromAsync - this is the preferred way to get an await-friendly wrapper around an APM-based async API such as those offered by WebRequest. This is far more efficient than using Task.Factory.StartNew as suggested by someone else, because that would spin up a new thread, whereas this won't need to.
With this in place, you can now write your code in the same way you would on platforms where these TAP-style methods are available (e.g. Windows 8 store apps, desktop apps, etc.):
public async Task GetEnvironmentVariablesAsync(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
// ASYNC: using awaitable wrapper to get request stream
using (var postStream = await request.GetRequestStreamAsync())
{
// Write to the request stream.
// ASYNC: writing to the POST stream can be slow
await postStream.WriteAsync(requestBody, 0, requestBody.Length);
}
try
{
// ASYNC: using awaitable wrapper to get response
var response = (HttpWebResponse) await request.GetResponseAsync();
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
// ASYNC: using StreamReader's async method to read to end, in case
// the stream i slarge.
string responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Note the four lines with // ASYNC: comments - these show where I've made changes. I've collapsed your method down to one, because that's a) possible once you're using async and await and b) much easier than trying to pass things from one method to the next using state arguments.
Notice that the second and fourth of these actually makes async some things you were previously doing synchronously: writing data into the request stream, and reading data out of the response stream. For a small request this probably doesn't matter, but if large amounts of data are being transferred, a synchronous call to Write or ReadToEnd may block. Fortunately, although Windows Phone 8 appears to be missing the TAP methods on WebRequest, it does offer them on Stream and StreamReader so this works without needing to write any extension methods.
I'm new to the community, so here goes my first post. In this case, you can return anytype using a generic Task. This has worked well for me in the past.
Server Side
public class MyController : ApiController
{
public Task<string> PostAsync()
{
return Task.Factory.StartNew(() =>
{
return "populate me with any type and data, but change the type in the response signature.";
});
}
}
Client Side
public class HomeController : Controller
{
public Task<ViewResult> Index()
{
return Task.Factory.StartNew(() =>
{
var model = "use a provider, get some data, or something";
return View(model);
});
}
}
This should do the job:
public async void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback) {
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject {
new JProperty("apiKey", _api),
new JProperty("affiliateId", _affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
var requestBody = Encoding.UTF8.GetBytes(serializedResult);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBody, 0, requestBody.Length);
await GetResponse(request);
}
private async Task GetResponse(WebRequest request) {
Stream resStream = null;
try {
var response = await request.GetResponseAsync();
if (response == null) {
return;
}
resStream = response.GetResponseStream();
if (resStream == null) {
return;
}
var reader = new StreamReader(resStream);
var responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err)) {
CredentialsCallback(Credentails);
}
else {
if (Credentails != null) {
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we) {
if (resStream != null) {
var reader = new StreamReader(resStream);
var responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
}
ErrorCallback(we);
}
}

.NET Threading - HttpWebRequest BeginGetResponse + AutoResetEvent

I would like to know which approach among the two is a better implementation ?
I need to create a web request which can range between 200ms to 5 seconds. I need the html response to proceed - so need to block on the main thread.
First Approach
string GetResponse()
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
IAsyncResult result = request.BeginGetResponse(null, null);
using (HttpWebResponse httpResponse = (HttpWebResponse)request.EndGetResponse(result))
{
using (Stream dataStream = httpResponse.GetResponseStream())
{
StreamReader reader = new StreamReader(dataStream);
response = reader.ReadToEnd();
}
}
Second Approach
string response = string.Empty;
AutoResetEvent waitHandle = null;
void GetResponse(string url)
{
waitHandle = new AutoResetEvent(false);
try
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
IAsyncResult asyncResult = request.BeginGetResponse(Callback, request);
waitHandle.WaitOne();
}
catch { }
finally
{
waitHandle.Close();
}
}
void Callback(IAsyncResult asyncResult)
{
HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
try
{
using (HttpWebResponse httpResponse = (HttpWebResponse)request.EndGetResponse(asyncResult))
{
if (httpResponse.StatusCode == HttpStatusCode.OK)
{
using (Stream dataStream = httpResponse.GetResponseStream())
{
StreamReader reader = new StreamReader(dataStream);
response = reader.ReadToEnd();
}
}
}
}
catch { }
finally
{
waitHandle.Set();
}
}
Why not execute the web request on the main thread? If you want the main thread to block, this is by far the easiest way to accomplish this.

Categories

Resources