Действительно, есть два варианта использования
- Вам небезразличен результат длительной операции
- Вам плевать на результат (выстрелите и забудьте)
Давайте начнем с первого случая:
public class BackgroundController : AsyncController
{
public void ExportAysnc(int id)
{
AsyncManager.OutstandingOperations.Increment();
Task.Factory.StartNew(() => DoLengthyOperation(id));
// Remark: if you don't use .NET 4.0 and the TPL
// you could manually start a new thread to do the job
}
public ActionResult ExportCompleted(SomeResult result)
{
return Json(result, JsonRequestBehavior.AllowGet);
}
private void DoLengthyOperation(int id)
{
// TODO: Make sure you handle exceptions here
// and ensure that you always call the AsyncManager.OutstandingOperations.Decrement()
// method at the end
SalesInvoice invoice = _salesService.GetById(id);
AsyncManager.Parameters["result"] = ExportTo3rdParty(invoice);
AsyncManager.OutstandingOperations.Decrement();
}
}
Теперь вы можете вызвать его так:
$.getJSON(
'<%= Url.Action("Export", "Background") %>',
{ id: $("#Id").val() },
function (data) {
// do something with the results
}
);
Теперь, когда вы упомянули вызов веб-службы, это означает, чтокогда вы сгенерировали клиентский прокси вашего веб-сервиса, у вас была возможность испускать асинхронные методы (XXXCompleted и XXXAsync):
public class BackgroundController : AsyncController
{
public void ExportAysnc(int id)
{
AsyncManager.OutstandingOperations.Increment();
// that's the web service client proxy that should
// contain the async versions of the methods
var someService = new SomeService();
someService.ExportTo3rdPartyCompleted += (sender, e) =>
{
// TODO: Make sure you handle exceptions here
// and ensure that you always call the AsyncManager.OutstandingOperations.Decrement()
// method at the end
AsyncManager.Parameters["result"] = e.Value;
AsyncManager.OutstandingOperations.Decrement();
};
var invoice = _salesService.GetById(id);
someService.ExportTo3rdPartyAsync(invoice);
}
public ActionResult ExportCompleted(SomeResult result)
{
return Json(result, JsonRequestBehavior.AllowGet);
}
}
Это наилучшее возможное использование асинхронного контроллера, поскольку он полагается на ввод-выводЗавершение Портирует и не монополизирует какие-либо потоки на сервере во время выполнения длительной операции.
Второй случай проще (на самом деле не нужен асинхронный контроллер):
public class BackgroundController : Controller
{
public ActionResult Export(int id)
{
// Fire and forget some lengthy operation
Task.Factory.StartNew(() => DoLengthyOperation(id));
// return immediately
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
}
Вот хорошая статья о MSDN об асинхронных контроллерах.