Ответ 1
Так как Windows Phone 8, похоже, не предлагает методы TAP, которые вам нужны, например GetRequestStreamAsync
, первое, что нужно сделать, это написать небольшую оболочку, чтобы предоставить их себе:
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);
}
}
Обратите внимание на использование Task.Factory.FromAsync
- это предпочтительный способ получить await
-дружественную оболочку вокруг асинхронного API на основе APM, такого как те, которые предлагаются WebRequest
. Это гораздо эффективнее, чем использование Task.Factory.StartNew
, как было предложено кем-то другим, потому что это запустило бы новый поток, тогда как это не нужно.
Теперь вы можете написать свой код так же, как на платформах, где доступны эти методы в стиле TAP (например, Windows 8 для хранения приложений, настольных приложений и т.д.):
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 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);
}
}
Обратите внимание на четыре строки с комментариями // ASYNC:
- они показывают, где я внес изменения. Я свернул ваш метод до одного, потому что это возможно: если вы используете async
и await
и b) намного проще, чем пытаться передать вещи от одного метода к другому с помощью аргументов состояния.
Обратите внимание, что вторая и четвертая из них фактически заставляют асинхронно выполнять некоторые вещи, которые вы ранее делали синхронно: записывая данные в поток запросов и считывая данные из потока ответов. Для небольшого запроса это, вероятно, не имеет значения, но если передаются большие объемы данных, синхронный вызов Write
или ReadToEnd
может блокироваться. К счастью, хотя в Windows Phone 8 отсутствуют методы TAP на WebRequest
, он предлагает их на Stream
и StreamReader
, поэтому это работает без необходимости писать какие-либо методы расширения.