Преобразование обычного веб-запроса Http Post с помощью Async и Await
Как я могу преобразовать мой традиционный вызов HttpWebRequest "POST" с шаблоном Async / Await, здесь с этим я прикрепляю свой текущий код, любой, пожалуйста, помогите мне преобразовать этот код с помощью шаблона Async / Await для 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);
}
}
3 ответов
поскольку Windows Phone 8, похоже, не предлагает методы крана, которые вам нужны, такие как 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
как предложил кто - то другой, потому что это будет вращать новый поток, тогда как это не будет нужно.
С этого места, теперь вы можете писать свой код так же, как на платформах, где эти кран-стиль методы (например, 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'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);
}
}
обратите внимание на четыре строки с // ASYNC:
комментарии-они показывают, где я внес изменения. Я свернул ваш метод до одного, потому что это a) возможно, как только вы используете async
и await
и b) гораздо проще, чем пытаться передать вещи от одного метода к другому использование аргументов состояния.
обратите внимание, что второй и четвертый из них фактически делает асинхронными некоторые вещи, которые вы ранее делали синхронно: запись данных в поток запросов и чтение данных из потока ответов. Для небольшого запроса это, вероятно, не имеет значения, но если передаются большие объемы данных, синхронный вызов Write
или ReadToEnd
могут заблокировать. К счастью, хотя Windows Phone 8, как представляется, отсутствует методы крана на WebRequest
, оно предложите их на Stream
и StreamReader
так это работает без необходимости писать какие-либо методы расширения.
Я новичок в сообществе, поэтому здесь идет мой первый пост. В этом случае можно вернуть anytype с помощью общей задачи. Это хорошо работало для меня в прошлом.
Сервер
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.";
});
}
}
Стороне Клиента
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);
});
}
}
Это должно сделать работу:
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);
}
}