it-roy-ru.com

Преобразование обычного веб-запроса Http Post с помощью Async и Await

Как я могу преобразовать мой традиционный вызов «POST» HttpWebRequest с помощью шаблона 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);

    }
} 
23
Nitha Paul

Поскольку 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-дружественную оболочку вокруг основанного на APM асинхронного API, такого как предлагаемый 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'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: - они показывают, где я внес изменения. Я свернул ваш метод до одного, потому что это а) возможно, если вы используете async и await и б) гораздо проще, чем пытаться передавать вещи из одного метода в другой с помощью аргументов состояния.

Обратите внимание, что второй и четвертый из них фактически делают асинхронными некоторые вещи, которые вы ранее делали синхронно: запись данных в поток запросов и чтение данных из потока ответов. Для небольшого запроса это, вероятно, не имеет значения, но если передаются большие объемы данных, синхронный вызов Write или ReadToEnd может блокироваться. К счастью, хотя в Windows Phone 8, по-видимому, отсутствуют методы TAP в WebRequest, он предлагает их для Stream и StreamReader, поэтому это работает без необходимости написания каких-либо методов расширения.

20
Ian Griffiths

Я новичок в сообществе, так что вот мой первый пост. В этом случае вы можете вернуть любой тип, используя универсальное задание. Это работало хорошо для меня в прошлом.

Серверная сторона  

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);
        });
    }
}
2
user586588

Это должно сделать работу:

    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);
        }
    }
0
lboshuizen