23

従来のHttpWebRequest「POST」呼び出しをAsync/Awaitパターンで変換する方法。これに現在のコードを添付します。WindowsPhone8のAsync/Awaitパターンを使用してこのコードを変換するのを手伝ってください。

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);

    }
} 
4

3 に答える 3

20

Since Windows Phone 8 doesn't seem to offer the TAP methods you need such as GetRequestStreamAsync the first thing to do is write a little wrapper to provide them for yourself:

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

Note the use of Task.Factory.FromAsync - this is the preferred way to get an await-friendly wrapper around an APM-based async API such as those offered by WebRequest. This is far more efficient than using Task.Factory.StartNew as suggested by someone else, because that would spin up a new thread, whereas this won't need to.

With this in place, you can now write your code in the same way you would on platforms where these TAP-style methods are available (e.g. Windows 8 store apps, desktop apps, etc.):

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);

    }
}

Note the four lines with // ASYNC: comments - these show where I've made changes. I've collapsed your method down to one, because that's a) possible once you're using async and await and b) much easier than trying to pass things from one method to the next using state arguments.

Notice that the second and fourth of these actually makes async some things you were previously doing synchronously: writing data into the request stream, and reading data out of the response stream. For a small request this probably doesn't matter, but if large amounts of data are being transferred, a synchronous call to Write or ReadToEnd may block. Fortunately, although Windows Phone 8 appears to be missing the TAP methods on WebRequest, it does offer them on Stream and StreamReader so this works without needing to write any extension methods.

于 2013-02-05T15:45:48.077 に答える
2

私はコミュニティに不慣れなので、これが私の最初の投稿になります。この場合、ジェネリック Task を使用して 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);
        });
    }
}
于 2013-01-30T20:17:35.460 に答える
0

これでうまくいくはずです:

    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);
        }
    }
于 2013-01-29T15:50:07.310 に答える