Coding this with .NET 4.5 and C# 5.0 async/await
is very easy.
You can make it work asynchronously with .NET 4.0 / C# 4.0 too, if you have to. You'd need to derive your controller from AsyncController
and use AsyncManager
. The basic steps are described in "Using an Asynchronous Controller in ASP.NET MVC".
In this light, your code may look like this (untested):
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
});
}
}
You could take it further and implement ReadToEndAsync
(as it is absent in .NET 4.0), but you won't be able to use using
. Check this for some more details.
Ideally, if you need to target ASP.NET MVC with .NET 4.0, but develop with VS2012+ in C# 5.0, you still can use async/await
, Microsoft provides Microsoft.Bcl.Async
library for that. Then your code might look like this:
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
});
}
}