WP7 synchronous web request - c#

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.

Related

Correct way to rewrite sync function with TAP

it might be a stupid question. I am rewriting a synchronous HTTP send data function to asynchronous with TAP.
The function looks like this:
public void SendToUrl(string url, string content)
{
try
{
byte[] payload = Encoding.ASCII.GetBytes(content);
Stopwatch sw = Stopwatch.StartNew();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "text/plain";
request.ContentLength = payload.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(payload, 0, payload.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
sw.Stop();
if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Accepted)
{
....
}
else
{
....
}
}
}
catch // error handling omitted
{
}
}
At first, I think it is very straightforward, just replace all sync .NET library functions with their awaitable XXXAsync counterparts and change function signature to public async void SendToUrlAsync(...) (because I use await inside the function), however, after having read some articles, it looks like lots of people say async void is not safe (could crash whole process), and it is designed for event handler only. Synchronous void function should be translated into async Task, even I do want a fire-and-forgot function here.
If that is true, to forcibly return a Task, I need to encapsulate whole code within a Task.Run(() => {...}) which looks like redundant and odd to me since I really don't care about the return Task object, but if I don't await it compiler will complain.
So, in my case, what is the recommended way to rewrite it? Thanks.
replace all sync .NET library functions with their awaitable XXXAsync counterparts and change function signature
Actually, if you slightly modify the steps here, it's a bit simpler:
Replace all sync APIs with their *Async equivalents.
await them.
The compiler will the give you an error suggesting the correct signature for you (in this case, async Task).
to forcibly return a Task, I need to encapsulate whole code within a Task.Run
Not at all. The async keyword will create a Task for you.
On a side note, the Write call is unsafe - it is possible for streams (network streams in particular) to only write a partial buffer.

WP8 Async/Await begingetresponse not waiting, gets run last

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.

HttpClient GetAsync hanging

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.

How to download data non asynchronously?

I want to download data non asynchronously in a Windows Phone application. I would make a downloader class, and have a simple method in it to download a string from a URL. On other platforms, I would use:
public class TextDownloader
{
public string GetString(string url)
{
WebClient web = new WebClient();
string s = web.DownloadString("http://www.google.com");
return s;
}
}
It would work well: simple, minimal code. However, the WebClient.DownloadString method is not available on Windows Phone 7, nor many WebRequest options. Are there any alternative ways to download data non asynchronously in Windows Phone? I would rather not have to create multiple events for download and error, just have a simple method return a value or throw an exception.
Indeed, you cannot use the synchronous model for downloads with WebClient out-of-the-box. This is by design, and given the nature of Windows Phone applications, you should follow this methodology.
The solution to your problem - callbacks. You can easily refactor your function to something like this:
public void GetString(string url, Action<string> onCompletion = null)
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (onCompletion != null)
onCompletion(e.Result);
};
client.DownloadStringAsync(new Uri(url));
}
This makes it relatively easy to use and trigger an action when it is completed. There is another way to do this as well, and that is - async/await. You will need to install the Bcl.Async package through NuGet:
Install-Package Microsoft.Bcl.Async -Pre
It would let you do this:
public async Task<string> DownloadString(string url)
{
WebClient client = new WebClient();
return await client.DownloadStringTaskAsync(url);
}
Still, though, it will be bound to the asynchronous model, just wrapped in a different manner and the thread will be waiting to get the string before returning it back to the caller.

HttpWebRequest.BeginGetRequestStream() best practice

I'm working on an async Http crawler that gathers data from various services, and at the moment, I'm working with threadpools that do serial HttpWebRequest calls to post/get data from the services.
I want to transition over to the async web calls (BeginGetRequestStream and BeginGetResponse), I need some way get the response data and POST stats (% completed with the write, when complete (when complete more important), etc). I currently have an event that is called from the object that spawns/contains the thread, signaling HTTP data has been received. Is there an event in the WebRequests I can attach to to call the already implemented event? That would be the most seamless for the transition.
Thanks for any help!!
The following code I just copy/pasted (and edited) from this article about asynchronous Web requests. It shows a basic pattern of how you can write asynchronous code in a somewhat organized fashion, while keeping track of what responses go with what requests, etc. When you're finished with the response, just fire an event that notifies the UI that a response finished.
private void ScanSites ()
{
// for each URL in the collection...
WebRequest request = HttpWebRequest.Create(uri);
// RequestState is a custom class to pass info
RequestState state = new RequestState(request, data);
IAsyncResult result = request.BeginGetResponse(
new AsyncCallback(UpdateItem),state);
}
private void UpdateItem (IAsyncResult result)
{
// grab the custom state object
RequestState state = (RequestState)result.AsyncState;
WebRequest request = (WebRequest)state.request;
// get the Response
HttpWebResponse response =
(HttpWebResponse )request.EndGetResponse(result);
// fire the event that notifies the UI that data has been retrieved...
}
Note you can replace the RequestState object with any sort of object you want that will help you keep track of things.
You are probably already doing this, but if not, I believe this is a perfectly acceptable and clean way to tackle the problem. If this isn't what you were looking for, let me know.
You could passing a delegate (as part of the async "state" parameter) that needs to be called. Then after your EndGetResponseStream do what you need and then call this delegate with any parameters you need.
Personally, since you're moving to the aysnc programming model (I assume to get better performance) I strongly suggest you move your workflow over to to asynchronous as well. This model allows you to process the results as they come in and as fast as possible without any blocking whatsoever.
Edit
On my blog there is an article
HttpWebRequest - Asynchronous Programming Model/Task.Factory.FromAsyc
on this subject. I'm currently in the process of writing it, but I've presented a class that I think you could use in your situation. Take a look at either the GetAsync method or PostAsync method depending on what you need.
public static void GetAsyncTask(string url, Action<HttpWebRequestCallbackState> responseCallback,
string contentType = "application/x-www-form-urlencoded")
Notice the responseCallback parameter? Well that's the delegate I talked about earlier.
Here is an example of how you'd call it (I'm showing the PostAsyn() method
var iterations = 100;
for (int i = 0; i < iterations; i++)
{
var postParameters = new NameValueCollection();
postParameters.Add("data", i.ToString());
HttpSocket.PostAsync(url, postParameters, callbackState =>
{
if (callbackState.Exception != null)
throw callbackState.Exception;
Console.WriteLine(HttpSocket.GetResponseText(callbackState.ResponseStream));
});
}
The loop could be your collection of urls. In the case of a GET you don't need to send any (POST) parameters and the callback is the lambda you see where I'm writing to the console. Here you could do what you need, of you could send in a delegate so the response processing is done "elsewhere".
Also the callback method is an
Action<HttpWebRequestCallbackState>
Where HttpWebRequestCallbackState is a custom class you can modify to include any information you need for your purposes. Or you could modify the signature to to an Action.
You can use the System.Net.WebClient class:
var client = new WebClient();
client.DownloadDataCompleted += (s, args) => { /* do stuff here */ };
client.DownloadDataAsync(new Uri("http://someuri.com/"));
The second method is my primary way of ending the response.
public string GetResponse()
{
// Get the original response.
var response = _request.GetResponse();
Status = ((HttpWebResponse) response).StatusDescription;
// Get the stream containing all content returned by the requested server.
_dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
var reader = new StreamReader(_dataStream);
// Read the content fully up to the end.
var responseFromServer = reader.ReadToEnd();
// Clean up the streams.
reader.Close();
if (_dataStream != null)
_dataStream.Close();
response.Close();
return responseFromServer;
}
/// <summary>
/// Custom timeout on responses
/// </summary>
/// <param name="millisec"></param>
/// <returns></returns>
public string GetResponse(int millisec)
{
//Spin off a new thread that's safe for an ASP.NET application pool.
var responseFromServer = "";
var resetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(arg =>
{
try
{
responseFromServer = GetResponse();
}
catch (Exception ex)
{
throw ex;
}
finally
{
resetEvent.Set();//end of thread
}
});
//handle a timeout with a asp.net thread safe method
WaitHandle.WaitAll(new WaitHandle[] { resetEvent }, millisec);
return responseFromServer;
}

Categories