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 ...
随机推荐
- javaScrip字符串(String)相关
-----------------------------------------此页只记录前端关于String的东西----------------------------------------- ...
- AWS之搭建深度学习主机
B.G 至2017.11 GPU选型:(参考知乎.CSDN) 高性价比的两款:GTX1080ti, Titan X --通常调试算法 i7CPU+32G内存+SSD+2*GPU(单块显存>6G ...
- pthread mutex
pthead_mutex_t mutex; 1:create: pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t ...
- 配置Jsp错误页面
配置Jsp错误页面一般我们有2种做法: (1)在页面中用指令进行配置,即page指令的errorPage和isErrorPage:可以使用page指令的errorPage来指定错误页!在当前JSP页面 ...
- Solr——Windows下部署Solr7.5.0至jetty、Tomcat
Solr6用默认的Jetty启动 需要的软件支持 JDK1.8以上 Solr6的安装包(solr-7.5.0.zip ) Solr自带一个Jetty环境,可以很方便的运行Solr. 直接到解压缩的so ...
- hive类型转化错误,会错误提示指定分区参数
select * from TRAD_LIST t WHERE t.dt >= '2017-10-18' and t.dt <= '2017-11-01' and t.con_level ...
- mysql 存储过程动态拼接sql并执行赋值
)) BEGIN ## 定义变量 ,) ; ## @表示全局变量 相当于php $ ## 拼接赋值 INTO 必须要用全局变量不然语句会报错 SET @strsql = CONCAT('SELECT ...
- 性能测试day02_后端网络协议架构
接着第一天的尾,继续来学习性能测试,上一次说到性能要大致经历哪些阶段,那么我们也来看下行业的做法: 行业有两种做法,一个是TPC,另一个是SPEC: TPC:指定业务类型,获得该指定业务的性能指标,也 ...
- .netLinq动态Where条件
文章介绍全网最佳方式使用EF+Linq实现多条件组合查询:代码中没有使用到网上主流自定义Expression表达式而是采用linq原生态功能编写示例直观.易懂,且有效解决自定义Expression不支 ...
- redis下操作Set和Zset
redis操作set 无序集合 元素为string类型 元素具有唯一性,不重复 命令 设置 添加元素 SADD key member [member ...] 获取 返回key集合所有的元素 SME ...