在开发ASP.NET应用程序时,经常需要实现定时任务调度功能。本文将探讨几种实现定时任务调度的方法,并以Workflow Foundation为例,详细说明如何创建和部署定时任务。
当考虑定时任务调度的解决方案时,通常会想到Windows服务和Windows任务计划程序。为了评估哪一种更适合需求,可以参考以下博客文章:
无论是任务计划程序还是Windows服务,都需要编写部署包或脚本。如果任务有任何更改,都需要更新所有运行服务或任务的服务器。
每个定时任务通常都是一个单独的应用程序(通常是控制台应用程序)。随着这类任务数量的增加,维护这些应用程序变得繁琐。然而,总是有例外。此外,任务计划程序中处理密码更改也有些问题。但是,如果愿意自动化这个过程,可以编写一些脚本。
在任务计划程序中,调度任务在几秒钟内运行可能是一个挑战。
根据MSDN的说明:使用cacls分配权限给任务文件夹的用户将能够访问所有用户计划的任务。请谨慎选择给任务文件夹分配权限的用户。
如果任务启动失败并出现错误,需要在每个任务中实现错误报告。
下面将直接进入代码部分。
不会详细介绍第一步。如果是ASP.NET的新手,可以参考。 打开Visual Studio 2010,选择新建项目,选择ASP.NET Web应用程序,输入项目名称并点击确定。
右键单击解决方案,选择添加 -> 新建项目... 工作流 -> 工作流控制台应用程序
它应该有一个要执行的任务和一个计时器来暂停/睡眠,在一个连续的while循环内。 可以使用与应用程序一起创建的默认工作流,或者创建一个新的。 添加一个While活动,条件设置为True。 在While活动中添加一个顺序活动。 在顺序活动中添加一个Invoke方法活动。 配置类和方法参数,方法应该有Public Static访问修饰符。 在顺序活动中的Invoke方法活动后添加一个Timer。 将计时器设置为适当的间隔。
XAML代码如下所示。
为了示例的目的,设置为每10秒调试一次。可以将InvokeMethod活动更改为调用各自的业务或服务组件上的适当方法。
以下是工作流的XAML代码示例。
<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="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:local="clr-namespace:WorkflowConsoleApplication" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 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="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" 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="http://schemas.microsoft.com/winfx/2006/xaml">
<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>
在Application_Start事件中加载并启动工作流运行时。 打开Global.asax.cs文件。 在Application_Start事件中,添加以下代码。将创建的工作流运行时对象添加到Application对象的集合中。
C#
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;
按照上述代码,在Application_Start事件中,可以启动工作流服务,如果这是预期在应用程序启动时启动的。在这段代码中,创建了一个工作流实例,类型为WorkflowConsoleApplication1.Workflow1,并启动它。
在Application_End事件中添加以下代码以停止工作流运行时。
System.Workflow.Runtime.WorkflowRuntime workflowRuntime = Application["WorkflowRuntime"] as System.Workflow.Runtime.WorkflowRuntime;
workflowRuntime.StopRuntime();
验证工作流是否完成了期望它完成的任务。
如果不希望在Application_Start事件中启动工作流,也可以通过点击网页上的按钮来执行相同的操作。可以通过应用程序的认证和授权来提供访问权限。
不需要为调度器单独部署包。 WF跟踪服务。 不需要额外配置或维护调度器。 在工作进程的安全上下文中运行。 可以实现基于角色的访问控制。 不需要服务器管理员的干预。