webrequest.begingetresponse is taking too much time when the url is invalid - c#

I am using webrequest to fetch some image data. The url may be invaild sometime. In case of invalid URL, begingetresponse is taking time equals to timeout period. Also the control become unresponsive during that period. In other word the async callback is not working asynchronously. Is this expected behaviour?
try
{
// Async requests
WebRequest request = WebRequest.Create(uri);
request.Timeout = RequestTimeOut;
RequestObject requestObject = new RequestObject();
requestObject.Request = request;
request.BeginGetResponse(this.ProcessImage, requestObject);
}
catch (Exception)
{
ShowErrorMessage(uri);
}
private void ProcessImage(IAsyncResult asyncResult)
{
try
{
RequestObject requestObject = (RequestObject)asyncResult.AsyncState;
WebRequest request = requestObject.Request;
WebResponse response = request.EndGetResponse(asyncResult);
Bitmap tile = new Bitmap(response.GetResponseStream());
// do something
}
catch (Exception)
{
ShowErrorMessage();
}
}

looks like this is an issue with .NET. BeginGetResponse blocks until DNS is resolved. In case of wrong URL (like http://somecrap) it tries until it gets timeout. See the following links -
link1 and link2

I just ran into this same situation. While it's not a perfect workaround I decided to use the Ping.SendAsync() to ping the site first. Good part is the async part return immediately. Bad part is the extra step AND not all sites respond to Ping requests.
public void Start(WatchArgs args)
{
var p = new System.Net.NetworkInformation.Ping();
args.State = p;
var po = new System.Net.NetworkInformation.PingOptions(10, true);
p.PingCompleted += new PingCompletedEventHandler(PingResponseReceived);
p.SendAsync(args.Machine.Name, 5 * 1000, Encoding.ASCII.GetBytes("watchdog"), po, args);
}
private void PingResponseReceived(object sender, .PingCompletedEventArgs e)
{
WatchArgs args = e.UserState as WatchArgs;
var p = args.State as System.Net.NetworkInformation.Ping;
p.PingCompleted -= new System.Net.NetworkInformation.PingCompletedEventHandler(HttpSmokeWatcher.PingResponseReceived);
args.State = null;
if (System.Net.NetworkInformation.IPStatus.Success == e.Reply.Status)
{
// ... BeginGetResponse now
}
else
{
/// ... machine not available
}
}
Just code and running for a day but initial result look promising.

Related

My desktop application hangs on web API service call with async and await

I am getting lots of delay when saving data in database. I have one exe (Deskptop Application) which reads data from serial port and push that entry in to database through web API service but my application get hangs on this line:
httpClient.PostAsync("api/MyController/Save", httpConent).Result;
This exe is responsible to call my web API service method and save data to my database.
This is my code:
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to whom ever interested
if (NewSerialDataRecieved != null)
{
NewSerialDataRecieved(this, new SerialDataEventArgs(data));
}
}
void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
{
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
//// Fired-off asynchronously; let the current thread continue.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
return;
}
//data is converted to text
string str = Encoding.ASCII.GetString(e.Data);
if (!string.IsNullOrEmpty(str))
{
CallWebservice(str)
}
}
public void CallWebservice(string xmlRequest)
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("WebService Url");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
StringContent httpConent = new StringContent(xmlRequest, Encoding.UTF8);
HttpResponseMessage responseMessage = null;
try
{
responseMessage = httpClient.PostAsync("api/MyController/Save", httpConent).Result;
}
catch (Exception ex)
{
if (responseMessage == null)
{
responseMessage = new HttpResponseMessage();
}
responseMessage.StatusCode = HttpStatusCode.InternalServerError;
responseMessage.ReasonPhrase = string.Format("RestHttpClient.SendRequest failed: {0}", ex);
}
}
}
My web api method:
public async Task<HttpResponseMessage> Save(HttpRequestMessage request)
{
var requestdata = request.Content.ReadAsStringAsync().Result;//extract Users Id's from this
var users=context.User.Where(t => (t.Stats == userId1) || (t.Stats == userId2)).ToList();
var objUsersMapping= new UsersMapping();
objUsersMapping.Work1 = users[0].Work1;
objUsersMapping.Work2 = users[1].Work1;
await this.SaveUsersMapping(objUsersMapping);
}
public async Task<UsersMapping> SaveUsersMapping(UsersMapping objUsersMapping)
{
using (var context = new MyEntities())
{
try
{
context.UsersMapping.Add(objUsersMapping);
await context.SaveChangesAsync();
return objUsersMapping;
}
catch (Exception foExe)
{
return null;
}
}
}
I haven't work much on Windows application so I am not understanding why my application is hanging.
Note: data will be continuously coming to my serial port so saving data through web service should not disturb _serialPort_DataReceived event.
This is a summary of my comments beneath the OP's question
You are calling an asynchronous method synchronously. That will cause the current thread to block. Get rid of the .Result and alter the rest of the code accordingly (like including async and await there too).
e.g. change this line
responseMessage = httpClient.PostAsync("api/MyController/Save", httpConent).Result;
...to:
responseMessage = await httpClient.PostAsync("api/MyController/Save", httpConent);
Your method signature will need to be changed as follows:
public async Task CallWebservice(string xmlRequest)
{
}
Any method that calls it will also need to be async and use await for example your _spManager_NewSerialDataRecieved() method.
Note it has been changed from void to async void. Note too the await prior to CallWebservice().
async void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
{
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
//// Fired-off asynchronously; let the current thread continue.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
return;
}
//data is converted to text
string str = Encoding.ASCII.GetString(e.Data);
if (!string.IsNullOrEmpty(str))
{
await CallWebservice(str)
}
}
A note on async void
Because the above method is an event handler it is fine for the method to be async void. Generally you want to avoid async void in non event handler code. For more info see this brilliant article by Mr Stephen Cleary.
Is this the only problem sir??
You should fix your async Save() method on the server too as it also has a .Result(). That will block the current thread on the server. Prefix it with a await. Generally you want to avoid .Result as a means to wait for the task to complete. It is safe to use as a means to obtain the result after you have awaited it, but there are more elegant ways to await and get the result in a single line of code. e.g. x = await FooAsync();.

How to call large number of http requests in a short period of time

I have to send 100,000 http requests every few seconds and with the code provided below it takes 19 seconds to send the requests and its longer than my interval.
During this time the CPU usage and Ethernet usage is 100% . I have tried it in a dual processor computer with a higher band width but the same result.
Is there any other way to have a better performance.
protected async void btnStartCallWhenAll_Click(object sender, EventArgs e)
{
t1 = DateTime.Now;
// Make a list of web addresses.
List<string> urlList = SetUpURLList(Convert.ToInt32(txtNoRecordsToAdd.Text));
// One-step async call.
await ProcessAllURLSAsync(urlList);
t2 = DateTime.Now;
double spent = t2.Subtract(t1).TotalMilliseconds;
txtTimeElapsed.Text = " Time Spent :" + spent.ToString() ;
}
private List<string> SetUpURLList(int No)
{
List<string> urls = new List<string>
{
};
for (int i = 1; i <= No; i++)
urls.Add("http://msdn.microsoft.com/library/windows/apps/br211380.aspx");
return urls;
}
private async Task ProcessAllURLSAsync(List<string> urlList)
{
ServicePointManager.UseNagleAlgorithm = true;
ServicePointManager.Expect100Continue = true;
ServicePointManager.CheckCertificateRevocationList = true;
ServicePointManager.MaxServicePointIdleTime = 10000;
ServicePointManager.DefaultConnectionLimit = 1000;
IEnumerable<Task> CallingTasksQuery =
from url in urlList select CallURLAsync(url);
Task[] CallingTasks = CallingTasksQuery.ToArray();
await Task.WhenAll(CallingTasks);
}
private async Task CallURLAsync(string url)
{
var content = new MemoryStream();
var webReq = (HttpWebRequest)WebRequest.Create(url);
using (WebResponse response = await webReq.GetResponseAsync())
{
}
}
Referring to HttpWebRequest is extremely slow!
Ensure you've set your:
webReq.Proxy = null;
It appears as though the startup of WebRequest will look for the default proxy.

how to wait for webclient OpenReadAsync to complete

I am using WebClient to download some stuff from internet in Windows Phone 8.1 app.
Below is the sample code i am using in my app - where i am calling below method, but my webclient is not waiting to complete the read operation and returning immediately after OpenReadAsync call.
how can i make sure that my method return operation must wait till OpenReadCompleted event is completed?
I have seen multiple similar questions, but couldn't find a solution.
MyCustomObject externalObj; // my custom object
private static void CheckNetworkFile()
{
try
{
WebClient webClient = new WebClient();
webClient.OpenReadCompleted += (s, e) =>
{
externalObj = myReadWebclientResponse(e.Result); // my custom method to read the response
};
webClient.OpenReadAsync(new Uri("http://externalURl.com/sample.xml", UriKind.Absolute));
}
catch (Exception)
{
externalObj = null;
}
}
I would advise you to use WebClient.OpenReadTaskAsync with a combination of the async/await keywords introduced in .NET 4.5 instead. You need to add the async keyword to your method, make it return a Task and it is advisable to end your method with the Async postfix:
MyCustomObject externalObj;
private static async Task CheckNetworkFileAsync()
{
try
{
WebClient webClient = new WebClient();
Stream stream = await webClient.OpenReadTaskAsync(new Uri("http://externalURl.com/sample.xml", UriKind.Absolute));
externalObj = myReadWebclientResponse(stream);
}
catch (Exception)
{
externalObj = null;
}
}
Edit:
As you said, WebClient.OpenReadTaskAsync isn't available for WP8.1, So lets create an Extension Method so it will be:
public static class WebClientExtensions
{
public static Task<Stream> OpenReadTaskAsync(this WebClient client, Uri uri)
{
var tcs = new TaskCompletionSource<Stream>();
OpenReadCompletedEventHandler openReadEventHandler = null;
openReadEventHandler = (sender, args) =>
{
try
{
tcs.SetResult(args.Result);
}
catch (Exception e)
{
tcs.SetException(e);
}
};
client.OpenReadCompleted += openReadEventHandler;
client.OpenReadAsync(uri);
return tcs.Task;
}
}
Now you can use it on your WebClient.
You can find great reading material in the async-await wiki and by simply filtering by that tag in the search bar.
I hope this is not too off topic, but others who are researching this might like to know that the above code sample can also be used for WCF calls in Silverlight. Be sure to add the Microsoft.Bcl.Async NuGet package first. Here is a WCF code example:
public static async Task<string> AuthenticateAsync(string userName, string password)
{
var dataAccessServiceClient = new DataAccessServiceClient("DataAccessService");
var taskCompletionSource = new TaskCompletionSource<string>();
EventHandler<AuthenticateCompletedEventArgs> completedHandler = null;
completedHandler = (s, args) =>
{
try
{
taskCompletionSource.SetResult(args.Result);
}
catch (Exception e)
{
taskCompletionSource.SetException(e);
}
};
dataAccessServiceClient.AuthenticateCompleted += completedHandler;
dataAccessServiceClient.AuthenticateAsync(userName, password);
return await taskCompletionSource.Task;
}
It can be called like this:
var result = await AuthenticateAsync(username, password);

Live Tiles not Updating

I'm trying to create a background agent that periodically updates a user's Live Tiles on Windows Phone.
Currently, my code for the agent is:
string where = "";
private GeoCoordinate MyCoordinate = null;
HttpWebResponse webResponse;
...
protected override void OnInvoke(ScheduledTask task)
{
System.Diagnostics.Debug.WriteLine("Invoked");
findMe();
NotifyComplete();
}
private void ResponseCallback(IAsyncResult asyncResult)
{
HttpWebRequest webRequest = (HttpWebRequest)asyncResult.AsyncState;
webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult);
MemoryStream tempStream = new MemoryStream();
webResponse.GetResponseStream().CopyTo(tempStream);
}
private async void findMe()
{
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracy = PositionAccuracy.High;
try
{
Geoposition currentPosition = await geolocator.GetGeopositionAsync(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10));
MyCoordinate = new GeoCoordinate(currentPosition.Coordinate.Latitude, currentPosition.Coordinate.Longitude);
// var uri = new Uri("http://www.streetdirectory.com//api/?mode=nearby&act=location&output=json&callback=foo&start=0&limit=1&country=sg&profile=template_1&x=" + MyCoordinate.Longitude + "&y=" + MyCoordinate.Latitude + "&dist=1");
// var client = new HttpClient();
var webRequest = (HttpWebRequest)HttpWebRequest.CreateHttp("http://www.streetdirectory.com//api/?mode=nearby&act=location&output=json&callback=foo&start=0&limit=1&country=sg&profile=template_1&x=" + MyCoordinate.Longitude + "&y=" + MyCoordinate.Latitude + "&dist=1");
webRequest.BeginGetResponse(new AsyncCallback(ResponseCallback), webRequest);
System.Diagnostics.Debug.WriteLine("findMe after response");
System.Diagnostics.Debug.WriteLine(MyCoordinate.Latitude);
System.Diagnostics.Debug.WriteLine(MyCoordinate.Longitude);
// var response = await client.GetStringAsync(uri);
System.Diagnostics.Debug.WriteLine(webResponse.ToString());
JToken token = JArray.Parse(webResponse.ToString())[0];
// JToken token = JArray.Parse(response)[0];
var name = token.Next.First.First;
var address = token.Next.Last.First;
where = name + ", " + address;
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("findMe died");
where = "";
}
System.Diagnostics.Debug.WriteLine("findMe complete");
UpdateAppTile();
}
private void UpdateAppTile()
{
System.Diagnostics.Debug.WriteLine("UpdateAppTile");
ShellTile appTile = ShellTile.ActiveTiles.First();
if (appTile != null)
{
StandardTileData tileData = new StandardTileData
{
BackContent = where
};
appTile.Update(tileData);
}
System.Diagnostics.Debug.WriteLine("Update Completed: " + where);
}
When I attempt to run this, the code reaches webRequest.BeginGetResponse and subsequently stops. The next line, and ResponseCallback are not reached.
An older version of my code is commented out, which I thought was the problem but it experienced the same problem as well.
The problem is that you are calling NotifyComplete() before the callback returns.
By calling NotifyComplete you're telling the OS that you've finished all your work and the agent can be terminated. Obviously this isn't the case when you're waiting for your webrequest callback.
The simple solution is to move this call into the callback method. obviously you'll need to handle error exceptions and the request timeout taking longer than the agent will wait for as well though.
Changing to using awaitable code may make this easier for you.

Parallel http requests

I have an app that making API requests to the last.fm website using the backgroundWorker. Initially I don't know how many request I'm gonna need to make. The response contains the total number of pages, so I will only get it after the first request. Here is the code below.
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
int page = 1;
int totalpages = 1;
while (page <= totalpages)
{
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
return;
}
//Here is the request part
string Response = RecentTracksRequest(username, from, page);
if (Response.Contains("lfm status=\"ok"))
{
totalpages = Convert.ToInt32(Regex.Match(Response, #"totalPages=.(\d+)").Groups[1].Value);
MatchCollection match = Regex.Matches(Response, "<track>((.|\n)*?)</track>");
foreach (Match m in match)
ParseTrack(m.Groups[1].Value);
}
else
{
MessageBox.Show("Error sending the request.", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (page >= totalpages)
break;
if (totalpages == 0)
break;
if (page < totalpages)
page++;
}
The problem is that the last.fm API is really slow and it might take up to 5 seconds to get the responce. With a big number of pages, the loading will take a long time.
I want to make parallel requests, say 3 parallel requests at a time. Is it possible? If yes, how can I make it?
Thanks a lot.
You can take advantage of HttpClient, assume you have list of urls:
var client = new HttpClient();
var tasks = urls.Select(url => client.GetAsync(url).ContinueWith(t =>
{
var response = t.Result;
response.EnsureSuccessStatusCode();
//Do something more
}));
If you use async method, you can await all tasks finish like below:
var results = await Task.WhenAll(tasks);
You can do Async Web Request as well, using BeginGetResponse
HttpWebRequest webRequest;
webRequest.BeginGetResponse(new AsyncCallback(callbackfunc), null);
void callbackfunc(IAsyncResult response)
{
webRequest.EndGetResponse(response);
}

Categories