ASP.NET 工作流:支持长时间运行操作的 Web 应用程序
在线浏览代码
本文将介绍以下内容:
|
本文使用了以下技术: Windows Workflow Foundation、ASP.NET |
- 从上一个活动获取订单数据。这通常是通过数据绑定完成的,稍后您可以看到它的示例。
- 从数据库中查找与该订单关联的客户。
- 根据该客户的位置从数据库中查找税率。
- 使用税率和与订单关联的订单项目进行一些简单的数学运算。
- 将税金总额存储在与后续活动绑定的属性中以完成结账过程。
- 通过从 Execute 方法返回“完成”状态标记向工作流运行时通知该活动已完成。
public class PasswordOperation : Operation {
Status ChangePassword(Guid userId, string pw) {
// Create a web service proxy:
UserService svc = new UserService();
// This can take up to 20 sec for
// the web server to respond:
bool result = svc.ChangePassword( userId, pw );
Logger.AccountAction( "User {0} changed pw ({1}).",
userId, result);
return Status.Completed;
}
}
public class PasswordOperation : Operation {
Status ChangePasswordImproved(Guid userId, string pw) {
// Create a web service proxy:
UserService svc = new UserService();
svc.ChangePasswordComplete += svc_ChangeComplete;
svc.ChangePasswordAsync( userId, pw );
return Status.Executing;
}
void svc_ChangeComplete(object sender, PasswordArgs e) {
Logger.AccountAction( "User {0} changed pw ({1}).",
e.UserID, e.Result );
Scheduler.SignalCompleted( this );
}
}
class MyActivity : Activity {
override ActivityExecutionStatus
Execute(ActivityExecutionContext ctx) {
// Do work here.
return ActivityExecutionStatus.Closed;
}
}
- 创建一个派生自 Activity 的类。
- 覆盖 Execute 方法。
- 创建一个工作流队列,用于接收所等待的异步事件已完成的通知。
- 订阅该队列的 QueueItemAvailable 事件。
- 启动长时间运行操作(例如发送电子邮件请经理审核工作岗位的申请)。
- 等待外部事件发生。这样可以有效地发出该活动已变为空闲的信号。可通过返回 ExecutionActivityStatus.Executing 向工作流运行时指出此情况。
- 事件发生时,处理 QueueItemAvailable 事件的方法会从队列中删除该项,然后将其转换为期望的数据类型并处理结果。
- 通常这样会终止活动的操作。然后工作流运行时通过返回 ActivityExecutionContext.CloseActivity 发出信号。
void AddService(object service)
C:\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\EN\
SqlWorkflowPersistenceService sqlSvc =
new SqlWorkflowPersistenceService(
@"server=.;database=WF_Persist;trusted_connection=true",
true, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10));
wfRuntime.AddService(sqlSvc);
- 求职者访问 Trey Research Web 站点并表示对某个工作岗位感兴趣。
- 向经理发送电子邮件通知有新的申请人。
- 该经理将审核申请并批准求职者得到某个特定的职位。
- 向该求职者发送电子邮件告知所提议职位的相关信息。
- 求职者会访问该 Web 站点接受或拒绝该职位。
public abstract class AsyncActivity : Activity {
private string queueName;
protected AsyncActivity(string queueName) {
this.queueName = queueName;
}
protected WorkflowQueue GetQueue(
ActivityExecutionContext ctx) {
var svc = ctx.GetService<WorkflowQueuingService>();
if (!svc.Exists(queueName))
return svc.CreateWorkflowQueue(queueName, false);
return svc.GetWorkflowQueue(queueName);
}
protected void SubscribeToItemAvailable(
ActivityExecutionContext ctx) {
GetQueue(ctx).QueueItemAvailable += queueItemAvailable;
}
private void queueItemAvailable(
object sender, QueueEventArgs e) {
ActivityExecutionContext ctx =
(ActivityExecutionContext)sender;
try { OnQueueItemAvailable(ctx); }
finally { ctx.CloseActivity(); }
}
protected abstract void OnQueueItemAvailable(
ActivityExecutionContext ctx);
}
- 开始长时间运行操作并调用 SubscribeToItemAvailable。
- 通知工作流运行时该活动处于空闲状态。
- 工作流实例通过持久性服务序列化为数据库。
- 操作结束时,将某个项目发送到工作流队列中。
- 这将触发工作流实例从数据库中还原。
- 抽象模板方法 OnQueueItemAvailable 由基类 AsyncActivity 执行。
- 该活动完成其操作。
public partial class AssignJobActivity : AsyncActivity {
public const string QUEUE NAME = "AssignJobQueue";
public AssignJobActivity()
: base(QUEUE_NAME)
{
InitializeComponent();
}
protected override ActivityExecutionStatus Execute(
ActivityExecutionContext ctx) {
// Runs before idle period:
SubscribeToItemAvailable(ctx);
return ActivityExecutionStatus.Executing;
}
protected override void OnQueueItemAvailable(
ActivityExecutionContext ctx) {
// Runs after idle period:
Job job = (Job)GetQueue(ctx).Dequeue();
// Assign job to employee, save in DB.
Employee employee = Database.FindEmployee(this.WorkflowInstanceId);
employee.Job = job.JobTitle;
employee.Salary = job.Salary;
}
}
protected void LinkButtonJoin_Click(
object sender, EventArgs e) {
WorkflowInstance wfInst =
Global.WorkflowRuntime.CreateWorkflow(typeof(MainWorkflow));
wfInst.Start();
Response.Redirect(
"GatherEmployeeData.aspx?id=" + wfInst.InstanceId);
}
public class AssignJobPage : System.Web.UI.Page {
/* Some details omitted */
void ButtonSubmit_Click(object sender, EventArgs e) {
Guid id = QueryStringData.GetWorkflowId();
WorkflowInstance wfInst = Global.WorkflowRuntime.GetWorkflow(id);
Job job = new Job();
job.JobTitle = DropDownListJob.SelectedValue;
job.Salary = Convert.ToDouble(TextBoxSalary.Text);
wfInst.EnqueueItem(AssignJobActivity.QUEUE_NAME, job, null, null);
buttonSubmit.Enabled = false;
LabelMessage.Text = "Email sent to new recruit.";
}
}
WorkflowInstance wfInst =
Global.WorkflowRuntime.GetWorkflow(id);
public class Global : HttpApplication {
public static WorkflowRuntime WorkflowRuntime { get; set; }
protected void Application_Start(object sender, EventArgs e) {
WorkflowRuntime = new WorkflowRuntime();
InstallPersistenceService();
WorkflowRuntime.StartRuntime();
// ...
}
protected void Application_End(object sender, EventArgs e) {
WorkflowRuntime.StopRuntime();
WorkflowRuntime.Dispose();
}
void InstallPersistenceService() {
// Code from listing 4.
}
}
ASP.NET 工作流:支持长时间运行操作的 Web 应用程序的更多相关文章
- [ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇]
借助.NET Core提供的承载(Hosting)系统,我们可以将任意一个或者多个长时间运行(Long-Running)的服务寄宿或者承载于托管进程中.ASP.NET Core应用仅仅是该承载系统的一 ...
- 三点经验:长时间运行函数需要随时发射信号报告进度,以及设置bool变量随时可以退出,每做一步操作必须及时记录和处理相关信息
三点经验:长时间运行函数需要随时发射信号报告进度,以及设置bool变量随时可以退出,每做一步操作必须及时记录和处理相关信息 不能到最后一起处理,否则万一中间出错了,这个记录状态就全部都乱了.
- 定时器解决js长时间运行脚本问题
一般地,单个js操作的运行时间不应超过100毫秒,否则的话,会影响用户体验,用户会认为自己与界面失去联系.而对于一些复杂的任务,可能无法在100ms内完成,甚至会突破浏览器限制(调用栈大小限制和长时间 ...
- WPF窗口长时间无人操作鼠标自动隐藏
在软件开发中有时会有等待一段时间无人操作后隐藏鼠标,可能原因大致如下: 1.为了安全性,特别是那些需要用到用户名和密码登录服务端的程序,常常考虑长期无人操作,程序自动跳转到用户登录界面: 2.软件为了 ...
- WinForm触摸屏程序功能界面长时间不操作自动关闭回到主界面 z
操作者经常会在执行了某操作后,没有返还主界面就结束了操作然后离开了,程序应该关闭功能窗体自动回到主界面方便下一位操作者操作.那么对于WinForm程序怎么实现呢? 实现原理:拦截Application ...
- WPF程序长时间无人操作
在软件开发中为了安全性,特别是那些需要用到用户名和密码登录服务端的程序,常常考虑长期无人操作,程序自动跳转到用户登录界面. 判断程序是否长时间无人操作,有两个依据,第一个是鼠标长时间不动,第二个是鼠标 ...
- Web页面长时间无操作后再获取焦点时转到登录界面
今天开始讲新浪博客搬到博客园. 在工作中遇到的小问题,感觉有点意思,就记录下来吧! 该问题分为两种情况,一.Web页面长时间无操作后,在对其进行操作,比如点击“首页”.“设 ...
- iOS开发笔记--如何实现程序长时间未操作退出
我们使用金融软件经常会发现手机锁屏或者长时间未操作就会退出程序或者需要重新输入密码等情况.下面让我们看一下如何实现这种功能.我们知道iOS有一个事件循环机制,也就是大家所说的runloop.我们在对程 ...
- WPF:鼠标长时间无操作,窗口隐藏
//设置鼠标长时间无操作计时器 private System.Timers.Timer MouseTimerTick = new System.Timers.Timer(10000); private ...
随机推荐
- Processing Binary Protocols with Client-Side JavaScript
http://blog.mgechev.com/2015/02/06/parsing-binary-protocol-data-javascript-typedarrays-blobs/ https: ...
- flume用场景及架构原理
Flume是什么 1.flume可以将采集到的数据存储到HDFS上,也可以放在Hbase上. 2.flume就是一个中间插件,他的作用就是屏蔽数据源和数据存储系统的差异.可以在不同的数据源采集数据,因 ...
- Guava实现 过滤文本,排序,转换内容,分组计数转换map 等等
重要点 :看注释 从access.log中统计数据 对healthcheck.html的请求不计入统计 输出请求总量,以及GET和POST分别的总量 输出请求最频繁的10个接口及其次数,按次数降序 输 ...
- Windows向虚拟机Linux传输文件方法
在Windows中装了个centOS,进行文件操作时,把mv写成了rm,然后就悲剧了.. 赶紧从网上找来文件的具体内容,然后由Windows向Linux挂载共享文件夹. 具体做法: 在Windows中 ...
- django 之admin使用
Admin注册 内容发布的部分由网站的管理员负责查看.添加.修改.删除数据,开发这些重复的功能是一件单调乏味.缺乏创造力的工作,为此,Django能够根据定义的模型类自动地生成管理模块. 1)准备工作 ...
- 压缩校验合并js之grunt搭建
1.在说grunt先认识几个grunt配置中的几个单词,concat(合并文件),uglify(压缩文件),jshint(检测代码规范),watch(实时监听修改的文件) 2.grunt是基于node ...
- StanFord ML 笔记 第五部分
1.朴素贝叶斯的多项式事件模型: 趁热打铁,直接看图理解模型的意思:具体求解可见下面大神给的例子,我这个是流程图. 在上篇笔记中,那个最基本的NB模型被称为多元伯努利事件模型(Multivariate ...
- uva-10887-枚举
题意:集合S1和S2,把S2中的元素拼接到S1的后面去,生成新的元素,问有多少个不重复的元素 直接map.注意,不能用cin读取字符串,题目没有保证字符串中间没有空格 #include "p ...
- 1.如何在Cloud Studio上执行Python代码?
1.在python文件下新建python文件,输入文件名后按Enter键生成,比如: one.py . 2.简单输入python代码: print "haha" 3.打开左下角的终 ...
- hping安装过程
转载: http://www.safecdn.cn/website-announcement/2018/12/hping-install/97.html Hping的主要功能有: 测试防火墙实用的 ...