I have an identical method in two of my WP8 apps. Given the same url and same device, the method works on one app, but not the other. In the failing app, GetAsync is hanging after it is called. No time out, no exception.
Here is the method in question.
private async Task<Byte[]> DownloadData(string uri)
{
byte[] myDataBuffer = null;
var newUri = new Uri(uri, UriKind.Absolute);
var myWebClient = new HttpClient();
var response = await myWebClient.GetAsync(newUri);
if (response.Content.Headers.ContentType.MediaType == "text/plain"
|| response.Content.Headers.ContentLength < 200)
{
throw new Exception(await response.Content.ReadAsStringAsync());
}
myDataBuffer = await response.Content.ReadAsByteArrayAsync();
return myDataBuffer;
}
This happens every time on one particular app, but not the other. Same device. Has anybody ever experienced this behavior? The url is valid, the code is identical. Is there a project setting somewhere that might affect this? I'm using the HttpClient in another portion of the failing app and it works there.
I can change the code to use a HttpWebRequest and that works fine. Just not the HttpClient.
I just now discovered that if I copy the method into my button_click handler, it works there too. Is there a problem having this method inside a separate class? That seems odd to me.
update
What seems to be breaking it is multiple layers of async methods calling it. Within the class I have
public override byte[] GetImageData(string imageUri)
{
return GetImageDataAsync(imageUri).Result;
}
public async Task<byte[]> GetImageDataAsync(string imageUri)
{
return await DownloadData(imageUri);
}
from my button_click handler, I'm calling GetImageData(uri). If I change that to await GetImageDataAsync(uri) it works.
Is Result not the correct property to reference in GetImageData?
Here's a test url "http://www.rei.com/pix/common/REI_logo.gif"
Calling Result or Wait can cause deadlocks, as I explain on my blog.
The proper way to solve this is to use await. I assume that there's some reason you want to synchronously block, but it's better to use await and find a way to make it work in your code.
Related
I'm basing myself on this sample:
async-example-with-HttpClient
I have the exact same code, which I'm running from a test:
public async Task<IEnumerable<Stuff>> GetStuff()
{
var r = await DownloadPage("http://stackoverflow.com");
}
static async Task<string> DownloadPage(string url)
{
using (var client = new HttpClient())
{
using (var r = await client.GetAsync(new Uri(url)))
{
string result = await r.Content.ReadAsStringAsync();
return result;
}
}
}
But it doesn't work. The debugger just stops on the await client.GetAsync(new Uri(url)) call.
There's no exception being thrown, there's nothing in the Visual Studio output window.
I have Fiddler open with all sessions cleared, I see nothing changing on doing that GET call.
I have nothing to go on why this doesn't work.
Any ideas on why this doesn't work and what I can do?
Update
This does partly work when called from an API, not from the xunit test I was starting with. But, when called from the API the response from the backend isn't received and the caller keeps waiting forever:
If I keep the code entirely on the API side, so no calls to any deeper dependencies, everything works. Context switching must be causing issues somehow.
I was reading the following topic http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
and decided to write a common utility method in my library to do a GET on remote url via HTTPClient
public static async Task<T> GetAsync<T>(HttpGetObject getObject)
{
string baseUrl = getObject.BaseUrl;
string actionUrl = getObject.ActionRelativeUrl;
string acceptType = getObject.AcceptType;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptType));
AddCustomHeadersToHttpClient(client, getObject);
// HTTP GET
HttpResponseMessage httpResponseMessage = await client.GetAsync(actionUrl).ConfigureAwait(false);
if (httpResponseMessage.IsSuccessStatusCode)
{
T response = await httpResponseMessage.Content.ReadAsAsync<T>().ConfigureAwait(false);
return response;
}
else
{
string message = httpResponseMessage.Content.ReadAsStringAsync().Result;
throw new Exception(message);
}
}
return default(T);
}
I know the "await httpResponseMessage.Content.ReadAsAsync().ConfigureAwait(false)" will prevent the deadlock in the above code
First:
My query is for "string message = httpResponseMessage.Content.ReadAsStringAsync().Result" line, will .Result can cause deadlock or not in that line?
Second:
If I call that code from UI like this:
public static object DoGet()
{
// Build getObject
var task = Utility.GetAsync(getObject);
task.Wait();
var response = task.Result;
return response;
}
Will that cause a deadlock?
Please note that I know to avoid all the mess with async-await, all the methods from UI to DAL must be async-await but I am not in position at this moment to change all that structure, my goal at this moment is to call HttpClient library and do a few GET operations.
So my questions is that will the above code can cause a deadlock?
Third:
Is task.Wait(); even needed in the above code?
In the general case, you should assume that yes, calling .Result or .Wait() on anything awaitable is dangerous and can deadlock (unless you are the library issuing the task, and you understand the full context). It is possible that it will work OK in some specific cases, but you should not rely on that behaviour, even if it works today.
In my C# app I need to have 2 distinct parts:
1) a Class Library, which wraps HttpClient, takes parameters, such as URI, and a JSON object to be POSTED, and invokes the POST method on an instance of HttpClient:
static async Task CreateCustomer()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://10.211.55.2:8080/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Accept", "application/json");
var customer = new Customer() { Name = "Gizmo", Address = "123 Widget lane" };
var response = await client.PostAsJsonAsync("/api/customer", customer);
var p = response;
}
}
2) A Windows Console app, which imports this Class Library, and invokes this CreateCustomer method, passing the actual parameter values for the URI and the Customer JSON object:
static async Task EnvokeCreateCustomer()
{
Customer customer = new Customer {Name="",Address="" };
var URI = "http://my_api:8080/Customer";
RestClient.Client restClient = new RestClient.Client();
restClient.CreateCustomer(URI, customer);
}
This code runs, but it is not event hitting my API, blows right passed it, and does nothing. Same issue with the GET API.
Is there a proven way to create such Class Libraries, which can be invoked by a Console app?
You don't await the method call:
await restClient.CreateCustomer(URI, customer);
Depending on the application host this may or may not make a noticeable difference. In a console application, where the application may simply do its thing and immediately terminate, it makes an enormous difference.
Not to mention any errors received in the process may go entirely unnoticed if the call is not awaited. So it's possible that there is a problem and it's trying to tell you what the problem is, but your code is simply ignoring it.
Surely there's a compiler warning pointing this out. Never ignore compiler warnings.
Side note: How does this code even compile? This:
restClient.CreateCustomer(URI, customer);
can't be calling this:
static async Task CreateCustomer()
If what you're showing us isn't your actual code, then all bets are off as far as answers go.
I may be misunderstanding the flow of control, because by all accounts this seems like it should work. This is a Windows phone 8 app. I am attempting to make a web request, and accordingly display the data returned. I am trying to get the data (here, called 'Key') in the following method:
public Task<String> getSingleStockQuote(String URI)
{
return Task.Run(() =>
{
String key = null;
HttpWebRequest request = HttpWebRequest.Create(URI) as HttpWebRequest;
HttpWebResponse response;
try
{
request.BeginGetResponse((asyncres) =>
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncres.AsyncState;
response = (HttpWebResponse)responseRequest.EndGetResponse(asyncres);
key = returnStringFromStream(response.GetResponseStream());
System.Diagnostics.Debug.WriteLine(key);
}, request);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("WebAccessRT getSingleStockQuote threw exception");
key = String.Empty;
}
return key;
});
}
...And I am calling this method like so:
WebAccessRT rt = new WebAccessRT();
await rt.getSingleStockQuote(stockTagURI);
System.Diagnostics.Debug.WriteLine("Past load data");
The WriteLine() in BeginGetResponse is for testing purposes; it prints after "Past Load Data". I want BeginGetResponse to run and complete operation (thus setting the Key), before the task returns. The data prints out right in the console, but not in the desired order - so Key is set and has a value, but its the very last part that gets run. Can someone point me in the right direction and/or see what's causing the problem above? Thinking this through, is the await operator SIMPLY waiting for the Task to return, which is returning after spinning off its async call?
BeginGetResponse starts an asynchronous process (hence the callback) so you cannot guarantee the order it is completed. Remember that the code within BeginGetResponse is actually a separate method (see closures) that is executed separately from getSingleStockQuote. You would need to use await GetResponseAsync or (imo, even better - you could greatly simplify your code) use HttpClient.
I’m developing a Windows Phone 7.1 application, and trying to implement tombstoning.
Due to the legal reasons I can’t save my view model. I’m only saving encrypted session ID, which can be used to load a view model data from the remote server.
On resume, I need to verify the session ID, if it’s expired – I take user to the login page of my app, if it’s still OK, I reload view model data from the server.
The problem is the HttpWebRequest lacks blocking API. Moreover, while inside page.OnNavigatedTo method after de-tombstoning, the method described here blocks forever.
I’ve worked around the problem by presenting my own splash screen.
However, I’d rather like to complete those RPC calls while the system-provided “Resuming…” splash screen is visible, i.e. before I return from page.OnNavigatedTo method.
Any ideas how can I complete HTTP requests synchronously while inside page.OnNavigatedTo after de-tombstoning?
Let me start out by saying that Microsoft really tries to push you to do async calls for good reasons, which is why I wanted to emphasize it.
Now if you really want to do it synchronous, I have an idea which I haven't been able to test myself. When using the HttpWebRequest class, there are two important functions, which you've probably used as well: BeginGetResponse and EndGetResponse.
These two functions work closely together. BeginGetResponse starts a asynchronous webrequest, where when the request is finished the EndGetResponse gives you to ouput when it's done. This is the way MS tries to let you do it. The trick to doing this stuff synchronously is that the beginGetResponse returns a IAsyncResult. This IAsyncResult interface contains a WaitHandler, which can be used to synchronously wait until the request is done. After which you can just continue with the endGetRequest and go on with your bussiness. The same thing goes for the BeginGetRequestStream and EndGetRequestStream.
But as I said before, I haven't tested this solution and it's purely theoretical. Let me know if it worked or not.
Good luck!
Update: another option is to use Reactive Extensions.
If you're on VS2010 you can install the AsyncCTP and when you do an extension method gets added that allows you to await the response.
static async Task<Stream> AsynchronousDownload(string url)
{
WebRequest request = WebRequest.Create(url);
WebResponse response = await request.GetResponseAsync();
return (response.GetResponseStream());
}
then:
UPDATED:
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var myResponse = await AsynchronousDownload("http://stackoverflow.com");
}
or
If you're using VS2012 you can install the Microsoft.Bcl.Async lib and do the same thing as if you were using the AsyncCTP, await the response.
or
You could implement something similar to Coroutines in Caliburn Micro. For this you implement the IResult interface.
public interface IResult
{
void Execute(ActionExecutionContext context);
event EventHandler<ResultCompletionEventArgs> Completed;
}
A possible implementation:
public class HttpWebRequestResult : IResult
{
public HttpWebRequest HttpWebRequest { get; set; }
public string Result { get; set; }
public HttpWebRequestResult(string url)
{
HttpWebRequest = (HttpWebRequest) HttpWebRequest.Create(url);
}
public void Execute (ActionExecutionContext context)
{
HttpWebRequest.BeginGetResponse (Callback, HttpWebRequest);
}
public void Callback (IAsyncResult asyncResult)
{
var httpWebRequest = (HttpWebRequest)asyncResult.AsyncState;
var httpWebResponse = (HttpWebResponse) httpWebRequest.EndGetResponse(asyncResult);
using (var reader = new StreamReader(httpWebResponse.GetResponseStream()))
Result = reader.ReadToEnd();
Completed (this, new ResultCompletionEventArgs ());
}
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
}
Then to call it:
var httpWebRequestResult = new HttpWebRequestResult("http://www.google.com");
yield return httpWebRequestResult;
var result = httpWebRequestResult.Result;
This might be an example of grabbing the Coroutines implementation from CM and using it separately.