在 ASP.NET 中使用工作流调度任务






4.50/5 (5投票s)
在 ASP.NET 中调度任务的众多方法之一
引言
在本文中,我想演示一种调度任务的方法。在这种情况下,我将使用工作流基础的 ASP.NET 应用程序。但是,首选的实现方式是使用任务计划程序或 Windows 服务作为主要选项。
我遇到了这些文章,它们解释了在 ASP.NET 中实现调度程序的不同方法
- http://msdn.microsoft.com/en-us/magazine/cc163821.aspx
- http://www.nayyeri.net/how-to-build-a-task-scheduler-system-for-the-asp-net-part-1
调度作业的注意事项
当我们考虑调度作业的解决方案时,Windows 服务和 Windows 任务计划程序会浮现在脑海中。如果您有兴趣评估哪个更好,请查看以下博客
部署 - 对于任务计划程序和 Windows 计划程序,我们需要编写部署包/脚本。如果对任务有任何更改,我们需要更新所有运行服务或任务的服务器。
维护 - 每个计划作业通常会变成一个单独的应用程序(主要是控制台)。随着此类作业数量的增加,维护这些应用程序会变得很麻烦。但是,总有例外。此外,处理密码更改是任务计划程序的一个小问题。但是,如果您想自动化这一点,可以编写一些脚本。
控制 - 在任务计划程序中,将任务安排在几秒钟内运行可能是一个挑战。
安全 - 来自 MSDN 的注意事项:通过使用 cacls 为 Tasks 文件夹分配权限的用户将能够访问所有用户的计划任务。请谨慎选择授予 Tasks 文件夹访问权限的用户。
错误处理和通知 - 如果任务启动失败并出错,我们需要在每个作业中实现错误报告。
Using the Code
我们直接进入一些代码。
步骤 1:创建您的 ASP.NET 应用程序
我不会详细介绍第一步。如果您不熟悉 ASP.NET,可以参考 ASP.NET。
打开 Visual Studio 2010,选择“新建项目”,选择“ASP.NET Web 应用程序”,输入项目名称,然后单击“确定”。
步骤 2:创建您选择的工作流应用程序
- 右键单击解决方案,选择“添加”->“新建项目…”
- 工作流 -> 工作流控制台应用程序
步骤 3:创建您的工作流,它应该有一个要执行的任务和一个在连续 while
循环中暂停/休眠的计时器。
- 您可以使用应用程序创建的默认工作流,也可以创建一个新的。
- 添加一个
While
活动,并将条件设置为True
。 - 在
While
活动中添加一个顺序活动。 - 将一个
Invoke
方法活动添加到顺序活动中 - 配置类和方法参数,方法应具有
Public Static
访问修饰符。 - 将
Timer
添加到顺序活动中的Invoke
方法活动之后。 - 将计时器设置为适当的间隔。
活动现在看起来应该像这样
上面工作流的 XAML 代码如下。
在本例中,我每隔 10 秒写入调试信息。您可以更改 InvokeMethod
活动以调用您各自的业务或服务组件中的适当方法。
<Activity mc:Ignorable="sap"
x:Class="WorkflowConsoleApplication.WorkflowWithScheduler"
sap:VirtualizedContainerService.HintSize="526,702"
mva:VisualBasic.Settings="Assembly references and imported namespaces
for internal implementation"
xmlns="<a href="http://schemas.microsoft.com/netfx/2009/xaml/activities">
http://schemas.microsoft.com/netfx/2009/xaml/activities</a>"
xmlns:local="clr-namespace:WorkflowConsoleApplication"
xmlns:mc="<a href="http://schemas.openxmlformats.org/markup-compatibility/2006">
http://schemas.openxmlformats.org/markup-compatibility/2006</a>"
xmlns:mv="clr-namespace:Microsoft.VisualBasic;assembly=System"
xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:s1="clr-namespace:System;assembly=System"
xmlns:s2="clr-namespace:System;assembly=System.Xml"
xmlns:s3="clr-namespace:System;assembly=System.Core"
xmlns:sad="clr-namespace:System.Activities.Debugger;
assembly=System.Activities"
xmlns:sap="<a href="http://schemas.microsoft.com/netfx/2009/
xaml/activities/presentation">http://schemas.microsoft.com/
netfx/2009/xaml/activities/presentation</a>"
xmlns:scg="clr-namespace:System.Collections.Generic;
assembly=System" xmlns:scg1="clr-namespace:System.Collections.
Generic;assembly=System.ServiceModel"
xmlns:scg2="clr-namespace:System.Collections.Generic;
assembly=System.Core" xmlns:scg3="
clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:sd="clr-namespace:System.Data;assembly=System.Data"
xmlns:sl="clr-namespace:System.Linq;assembly=System.Core"
xmlns:st="clr-namespace:System.Text;assembly=mscorlib"
xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">
http://schemas.microsoft.com/winfx/2006/xaml</a>">
<Sequence sad:XamlDebuggerXmlReader.FileName="C:\Users\Chinna\documents\
visual studio 2010\Projects\SchedulerSample\WorkflowConsoleApplication1\
WorkflowWithScheduler.xaml" sap:VirtualizedContainerService.HintSize="486,657">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<While sap:VirtualizedContainerService.HintSize="464,533" Condition="True">
<Sequence sap:VirtualizedContainerService.HintSize="438,417">
<sap:WorkflowViewStateService.ViewState>
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
</scg3:Dictionary>
</sap:WorkflowViewStateService.ViewState>
<InvokeMethod sap:VirtualizedContainerService.HintSize="218,130"
MethodName="WriteDebug" TargetType="local:MyClass" />
<WriteLine sap:VirtualizedContainerService.HintSize="218,61" Text="testing it..." />
<Delay Duration="00:00:10" sap:VirtualizedContainerService.HintSize="218,22" />
</Sequence>
</While>
</Sequence>
</Activity></span>
步骤 4:设置和启动工作流运行时
加载和启动工作流运行时在 Application_Start
事件中完成。
- 打开
Global.asax.cs
文件 - 在
Application_Start
事件中,添加以下代码。我们将创建的WorkflowRuntime
对象的引用添加到Application
对象集合中。
System.Workflow.Runtime.WorkflowRuntime
workflowRuntime = new System.Workflow.Runtime.WorkflowRuntime();
System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService
manualService = new
System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService();
workflowRuntime.AddService(manualService);
workflowRuntime.StartRuntime();
Application["WorkflowRuntime"] =
workflowRuntime;
步骤 5:在 ASP.NET 应用程序启动时启动工作流。
遵循 Application_Start
事件中的上述代码,您可以启动工作流服务,如果它应该在应用程序启动时启动。在此代码中,我们正在创建一个类型为 WorkflowConsoleApplication1.Workflow1
的工作流实例并启动它。
步骤 6:在 ASP.NET 应用程序停止时停止工作流服务。
在 Application_End
事件中添加以下代码以停止工作流运行时。
System.Workflow.Runtime.WorkflowRuntime workflowRuntime =
Application["WorkflowRuntime"] as System.Workflow.Runtime.WorkflowRuntime;
workflowRuntime.StopRuntime();</span>
步骤 7:使用 ASP.NET 测试调度程序。
验证工作流是否已执行您期望的任务。
步骤 8:方便地启动/停止工作流
如果您不希望在 Application_Start
事件中启动工作流,则可以在其中一个网页上的按钮单击时执行此操作。应用程序的身份验证和授权可以提供对此的访问。
优点
- 无需为调度程序单独部署包
- WF 跟踪服务
- 无需对调度程序进行额外配置或维护
- 在工作进程的安全上下文中运行
- 可以实现基于角色的访问,以允许控制工作流
- 不需要服务器管理员干预
缺点
- 这不是处理计划任务的传统方法
- 由于关键的架构差异,在设计启用工作流的 ASP.NET 应用程序时应考虑托管基础结构。
- 应用程序的设计应考虑到应用程序的可维护性。
历史
- 2011年6月23日:初稿