Although implementing it is not that hard, I’m not a big fan of the current syntax(The new async api in ASP.NET MVC 4 looks promising).
In the meanwhile I have written a small helper class to simplify the usage of the AsyncController.
public static class AsyncManagerExtensions
{
public static void RegisterTask<T>(this AsyncManager asyncManager, Task<T> task, Func<T, object> func)
{
asyncManager.OutstandingOperations.Increment();
task.ContinueWith(task2 =>
{
object propertyObject = null;
if (!task2.IsFaulted)
{
//invoke the provided function with the
//result of running the task
propertyObject = func(task2.Result);
}
else
{
propertyObject = func(default(T));
}
//use reflection to set asyncManager.Parameters
//for the returned object's fields and properties
var ty = propertyObject.GetType();
foreach (var f in ty.GetFields())
{
asyncManager.Parameters[f.Name] = f.GetValue(propertyObject);
}
foreach (var p in ty.GetProperties())
{
var v = p.GetGetMethod().Invoke(propertyObject, null);
asyncManager.Parameters[p.Name] = v;
}
asyncManager.OutstandingOperations.Decrement();
});
}
}
Using it is simple. I create a controller that inherits from AsyncController:
public class PrintController : AsyncController
{
private readonly IReportService _reportService;
public PrintController(IReportService reportService)
{
_reportService = reportService;
}
}
I add a method that returns the Task I want to execute and and the Action Controller method that will be called by the View(in this case through /Print/Pdf) . In this Action Controller method I call the RegisterTask<T> extension method and pass 2 properties:
- The method that needs to be executed
- An expression that takes the output of the task and maps it to the parameters of the Completed method(based on the parameter name).
public void PdfAsync(string reportName)
{
AsyncManager.RegisterTask<byte[]>(RenderReport(reportName)), renderReportResult=> new { data = renderReportResult, reportName = reportName });
}
private Task<byte[]> RenderReport(string reportName)
{
return Task.Factory.StartNew(()=>_reportService.RenderReport(reportName));
}
public ActionResult PdfCompleted(byte[] data, string reportName)
{
var fileName = reportName + ".pdf";
var fileContentResult = File(data, "application/pdf", fileName);
Response.AppendHeader("Content-Disposition", string.Format("inline; filename={0}", fileName));
return fileContentResult;
}
0 comments:
Post a Comment