How to create a web request asynchronously without a callback

I have a service that talks with a third party on the Internet, if I want it to scale, I do not want my threads to be blocked, waiting for a response when they can handle new requests. One way is to use the httpRequest.BeginGetResponse method and pass the callback. The problem with this is that this method returns immediately, and I have nothing to return to the caller of my service. Once in a callback, I cannot do anything useful.

What I would like is something like this

public string CallServiceNonBlocking(string url) {

   var httpRequest = (HttpWebRequest)WebRequest.Create(url);

   HttpResponse res = httpRequest.FetchNonBlocking(); //this does the work but my thread should  be returned to the asp.net thread pool to do other work rather than blocking here

   return res.GetValue(); 

}

Note. I don't have .Net 4.5 for me, only .NET 4. But for reference, can I see a solution for both versions?

+4
2

.NET 4.5 # 5.0 async/await .

.NET 4.0/# 4.0, . AsyncController AsyncManager. " ASP.NET MVC" .

():

static public Task<WebResponse> GetResponseTapAsync(this WebRequest request)
{
    return Task.Factory.FromAsync(
         (asyncCallback, state) =>
             request.BeginGetResponse(asyncCallback, state),
         (asyncResult) =>
             request.EndGetResponse(asyncResult), null);
}

// ...

public class YourController : AsyncController
{
    public void YourMethodAsyc(string url)
    {
        AsyncManager.OutstandingOperations.Increment();

        var request = (HttpWebRequest)WebRequest.Create(url);
        request.GetResponseTapAsync().ContinueWith(responseTask =>
        {
            try
            {
                var stream = responseTask.Result.GetResponseStream();
                using (var streamReader = new StreamReader(stream))
                {
                    // still blocking here, see notes below
                    var data = streamReader.ReadToEnd();

                    AsyncManager.Parameters["data"] = data;
                }
            }
            finally
            {
                AsyncManager.OutstandingOperations.Decrement();
            }
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }

    public ActionResult YourMethodCompleted(string data)
    {
        return View("Data", new ViewModel
        {
            Data = data
        });
    }
}

ReadToEndAsync ( .NET 4.0), using. .

, ASP.NET MVC .NET 4.0, VS2012 + # 5.0, async/await, Microsoft Microsoft.Bcl.Async. :

public class YourController : AsyncController
{
    async Task<string> YourMethodAsyncImpl(string url)
    {
        var request = (HttpWebRequest)WebRequest.Create(url);
        using (var response = await request.GetResponseAsync()
        using (var streamReader = new StreamReader(response.GetResponseStream())
            return await streamReader.ReadToEndAsync();
    }

    public void YourMethodAsyc(string url)
    {
        AsyncManager.OutstandingOperations.Increment();

        YourMethodAsyncImpl(url).ContinueWith(resultTask =>
        {
            try
            {
                AsyncManager.Parameters["data"] = resultTask.Result;
            }
            finally
            {
                AsyncManager.OutstandingOperations.Decrement();
            }
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }

    public ActionResult YourMethodCompleted(string data)
    {
        return View("Data", new ViewModel
        {
            Data = data
        });
    }
}
+2

Microsoft Reactive Framework . (NuGet "Rx-Main" )

.

:

public IObservable<string> CallServiceNonBlocking(string url)
{
    return Observable.Start(() =>
    {
        var httpRequest = (HttpWebRequest)WebRequest.Create(url);
        HttpResponse res = httpRequest.FetchBlocking();
        return res.GetValue(); 
    });
}

:

CallServiceNonBlocking(url)
    .Subscribe(response =>
    {
        /* handle response here */
    });

ObserveOn, , ..

0

Source: https://habr.com/ru/post/1533932/


All Articles