【问题标题】:Show a popup message after completion of WorkFlow 4 from the controller MVC从控制器 MVC 完成 WorkFlow 4 后显示弹出消息
【发布时间】:2011-08-03 15:01:14
【问题描述】:

我是 WorkFlow 4 (WF 4) 的初学者,我在 MVC 3 中使用它时遇到了一个严重的问题,我在网上找不到答案。

如果工作流程中发生异常或输出参数中返回任何内容,我需要显示弹出消息,我有一个用户可以编辑的页面,最后他将单击“保存”按钮。

单击“保存”按钮会将表单提交给控制器并运行工作流,当工作流完成时,我会得到一个输出,说明通过工作流更新数据是否成功,然后我需要在完成操作时显示此状态,但我不能,因为我异步运行它,这意味着该方法将返回给用户,同时工作流正在调用该事件。

这是我在控制器中的代码:

[HttpPost()]
    public ActionResult SaveVehicles(vehiclesData model) {
   Services.VehiclesDataUpdate vehiclesDataUpdate = new Services.VehiclesDataUpdate(this.SessionData.DealerLotKey, null, null);
            IDictionary<string, object> parameters = new Dictionary<string, object>();
            parameters.Add("VehiclesDataUpdate", vehiclesDataUpdate);
            parameters.Add("UnionVehicles", unionVehicles);
            parameters.Add("SolrVehicles", solrVehicles);

            IDictionary<string, object> outputs = new Dictionary<string, object>();
            AutoResetEvent syncEvent = new AutoResetEvent(false);
            WorkflowApplication wfApp = new WorkflowApplication(new VehiclesUpdate(), parameters);

            wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e) {
                outputs = e.Outputs;
                 syncEvent.Set();

                if (!errorExceptions.IsNullOrEmpty()) {
                    //TODO: Render a parital view to display an error message or the result of the workflow in the ouptput
                    //TODO: Logging.
                }
            };

            wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e) {
                syncEvent.Set();
            };

            wfApp.Run();

 return View(model);
    }

如何在工作流完成后将内容发送回用户?

提前致谢。

【问题讨论】:

  • WorkflowInvoker 或使用 ManualResetEvent 向 ASP.NET 工作线程发出工作流应用程序已完成执行的信号。
  • 你能给我举个例子吗?
  • 这里有很多。浏览 [wf4] 并阅读。我不会回答,因为我相信在 ASP.NET 中使用 asynchronous pages 可能会有更好的解决方案。问题是我对此还不够熟悉,无法给出充分的答案。

标签: asp.net-mvc workflow-foundation-4 workflowservice


【解决方案1】:

如果您想从 MVC 操作运行工作流,可以使用多种方法。首先,您可以像以前一样使用 WorkflowApplication。我已经修改了代码以使用更适合 WorkflowApplication 的 AyncController。

public class HomeController : AsyncController
{
    [HttpPost()]
    public void SaveVehiclesAsync(vehiclesData model)
    {
        Services.VehiclesDataUpdate vehiclesDataUpdate = new Services.VehiclesDataUpdate(this.SessionData.DealerLotKey, null, null);
        IDictionary<string, object> parameters = new Dictionary<string, object>();
        parameters.Add("VehiclesDataUpdate", vehiclesDataUpdate);
        parameters.Add("UnionVehicles", unionVehicles);
        parameters.Add("SolrVehicles", solrVehicles);

        WorkflowApplication wfApp = new WorkflowApplication(new VehiclesUpdate(), parameters);

        wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e) {
            AsyncManager.Parameters["outputs"] = e.Outputs;
            AsyncManager.OutstandingOperations.Decrement();
        };

        wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e) {
           AsyncManager.OutstandingOperations.Decrement();
        };

        AsyncManager.OutstandingOperations.Increment();
        wfApp.Run();
    }

    public ActionResult IndexCompleted(IDictionary<string, object> outputs)
    {
        var model = outputs["model"];
        return View(model);
    }
}

但是,这可能并不总是最好的解决方案。一般来说,一个 ASP.NET 服务器会很忙,以使所有内核都满意,因此异步处理只会损害扩展能力。现在,如果您的工作流主要执行异步 IO,这很好,但如果它正在执行同步 IO 或处理,则使用 WorkflowInvoker 可能会更好。

代码应该是这样的。

public class HomeController : Controller
{
    [HttpPost()]
    public ActionResult SaveVehicles(vehiclesData model)
    {
        Services.VehiclesDataUpdate vehiclesDataUpdate = new Services.VehiclesDataUpdate(this.SessionData.DealerLotKey, null, null);
        IDictionary<string, object> parameters = new Dictionary<string, object>();
        parameters.Add("VehiclesDataUpdate", vehiclesDataUpdate);
        parameters.Add("UnionVehicles", unionVehicles);
        parameters.Add("SolrVehicles", solrVehicles);

        IDictionary<string, object> outputs = WorkflowInvoker.Invoke(new VehiclesUpdate(), parameters);

        var model = outputs["model"];
        return View(model);
    }
}

注意:代码是否仅使用 Notepad++,因此请注意小的语法错误。

【讨论】:

  • @Mautice:首先,非常感谢你的回答,它让我对很多事情大开眼界。我正在做异步方式。我现在明白它是如何工作的,但是 SaveVehiclesAsync() 是一个不会返回任何东西的 void 方法,在我的情况下,我想在工作流处理时向用户返回一些东西,然后当工作流完成时,我将向用户返回不同的东西。例如,在工作流完成之前,我如何实现 SaveVehiclesAsync() 以返回视图。
  • 查看this 帖子,了解在服务器进程仍处于活动状态时向浏览器发送更新的方法。
  • 另一件事,这个工作流不应该是异步独立运行的吗这对吗?
  • 没有。就浏览器而言,您只是中止一个请求并声明一个新请求。服务器无法阻止这种情况,只有客户端 JavaScript 可以提供帮助。
  • 那么你是说如果工作需要 40 秒才能完成并且用户想要导航到不同的页面,他应该等到工作完成???