ASP.NET MVC2从jQuery调用AsyncController方法?

时间:2011-02-19 22:27:03

标签: c# jquery asp.net-mvc-2 asynccontroller

我正在尝试学习如何在MVC2中使用AsyncController,但是那里的文档/教程很少。我正在寻找一种普通的控制器方法,它对第三方服务的导出非常慢,并将其转换为异步方法。

原始控制器方法:

public JsonResult SaveSalesInvoice(SalesInvoice invoice)
{
    SaveInvoiceToDatabase(invoice); // this is very quick 
    ExportTo3rdParty(invoice); // this is very slow and should be async
}

所以我创建了一个继承自AsyncController的新控制器:

public class BackgroundController : AsyncController
{
    public void ExportAysnc(int id)
    {
        SalesInvoice invoice = _salesService.GetById(id);
        ExportTo3rdParty(invoice);
    }

    public void ExportCompleted(int id)
    {
         // I dont care about the return value right now, 
         // because the ExportTo3rdParty() method
         // logs the result to a table
    }

    public void Hello(int id)
    {            
    }
}

然后从jQuery调用Export方法:

function Export() {
    $.post("Background/Export", { id: $("#Id").val() }, function (data) {
    // nothing to do yet
    });
}

但结果是404未找到错误(未找到后台/导出)。如果我尝试调用Background / Hello或Background / ExportAysnc,则会找到它们。

我做错了什么?

1 个答案:

答案 0 :(得分:8)

确实有两个用例

  1. 您关心漫长操作的结果
  2. 你不关心结果(火与忘记)
  3. 让我们从第一个案例开始:

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

    现在因为您提到了一个Web服务调用,这意味着当您生成Web服务的客户端代理时,您有机会发出异步方法(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);
        }
    }
    

    这是异步控制器的最佳使用方法,因为它依赖于I / O完成端口,并且在执行冗长操作期间不会独占服务器上的任何线程。


    第二种情况更容易(不需要异步控制器):

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

    这是Async控制器上的nice article on MSDN