2

我正在开发一个 MVC 3 Web 应用程序(.NET Framework 4、IIS7),它充当基于某些遗留技术构建的自定义 ID 卡打印机的前端。无需过多介绍详细信息,当单击“打印”时,Web 应用程序会将带有卡片信息的行写入数据库并返回。然后后端的服务获取该行并处理卡片的实际打印。后端服务完成后,它会使用指示成功或失败的状态列更新该行。

现在,应用程序 POST 数据(通过 jquery ajax),一旦将行写入数据库,控制器就会返回成功,并显示给用户。由于我所描述的设置,这可能会或可能不会真正反映现实,因为服务或卡片打印机可能有问题。

我们有一个新要求,即根据服务对行的更新,使 UI “等待”更新或成功或失败。它已经通过 jquery ajax 调用在客户端以异步方式设置,我不担心在前端处理它。我看过 SignalR 之类的,并涵盖了它的这一部分。

我正在寻找的是有关如何在 Web 服务器端正确处理它的信息(链接和文章,而不是解决方案)。我不想在从早期请求定期轮询数据库时阻止传入的打印请求。从高层次来看,我想知道设置控制器和必要的后台进程的最佳方法是什么:

  1. 接受请求并将行写入数据库
  2. 设置后台轮询进程,然后将控制权返回给 ASP.net
  3. 经常轮询数据库,直到行被更新(或达到超时)
  4. 回复客户

我不是线程方面的专家,但我知道如果这样做不正确,我会处于危险的境地。任何帮助是极大的赞赏。

4

2 回答 2

1

我会发表评论,但我没有足够的代表。

为什么将重点放在服务器推送到 UI 上?您说表单将行写入数据库,然后在屏幕上显示“成功”,这可能不是真实的状态。在打印过程中的任何时候,您都可以查询数据库并找到最新状态吗?

是否有什么东西阻止您让 UI 每 X 秒更新一次具有最新状态的页面部分?让 UI 拉取信息而不是服务器将其推出。

我有一个页面显示来自数据库的日志记录。每天都会有一个进程开始向日志写入更多记录,并且具有自动刷新功能来监视该进程很有用。在那个页面上,我有一个 Ajax 表单,它向控制器发出请求,控制器在局部视图中输出一个新表。这个局部视图被放入UpdateTargetIdAjax 表单中。对于自动刷新,我利用 javascriptsetInterval()函数每 X 秒提交一次 Ajax 表单。还可以指定其他回调,例如OnSuccess您可以在哪里检查特定的返回条件。

Ajax.BeginForm 的 AjaxOptions 类

示例表格

w3schools 的 setInterval()

于 2013-01-30T21:36:47.857 回答
0

这是我完成它的方式的一些伪代码。我已经测试过它不会阻止额外的传入请求,并且在处理多个并发请求时表现正确。但是,这确实会在 task.Wait() 处阻塞,因此在负载下,我想如果线程池配置不正确,它会遇到性能问题。根据我对 merekel 的评论,最后我可能会使用客户端轮询解决方案,而不是这样:

public class MyController : AsyncController 
{
    public void SaveAndPrintAsync(CardData data)
    {
        if (data == null)
            throw new ArgumentNullException("data", "data cannot be null");

        // 1. Accept the request and write the row to the database
        var result = _databaseFacade.Save(data);
        AsyncManager.Parameters["result"] = result;

        // 2. set up a background polling process, then return control to ASP.net
        AsyncManager.OutstandingOperations.Increment();
        var task = _databaseFacade.GetPrintStatusAsync(data);
        task.ContinueWith(t =>
        {
            AsyncManager.OutstandingOperations.Decrement();
        });
        task.Wait();
        AsyncManager.Parameters["status"] = task.Result;
    }

    public JsonResult SaveAndPrintCompleted(PrintResult result, PrintStatus status)
    {
        try // return an answer to the client
        {  
            if (status == PrintStatus.Printed)
                return Json(result);

            throw new ApplicationException("An error occurred while printing. Please try again.");
        }
        catch (Exception ex)
        {
            return FormatError(ex); // returns Json
        }
    }
}

public class DatabaseFacade 
{
    public Task<PrintStatus> GetPrintStatusAsync(CardData data)
    {
       var task = Task.Factory.StartNew(() =>
           {
               var counter = 0;
               var status = PrintStatus.Waiting;
               do
               {
                   ++counter;
                   var queue = _myDBContext.FindById<CardData>(data.ID);

                   if (queue != null)
                       status = (PrintStatus)Enum.Parse(typeof (PrintStatus), queue.PrintStatus.ToString());

                   if (status == PrintStatus.Waiting || status == PrintStatus.Printing)
                       Thread.Sleep(1000);

               } while (counter < 5 && (status == PrintStatus.Waiting || status == PrintStatus.Printing));
               return status;
           }, TaskCreationOptions.LongRunning);
       return task;
    }
}
于 2013-01-30T23:31:03.960 回答