我正在进行的项目要求在某个时间执行一些执行。我不确定处理这种情况的最佳方法是什么。该方法必须能够在服务器重启/维护后继续存在。方法调用必须以编程方式进行。
我正在考虑走这条道路:
我可以在数据库(甚至是消息队列)中创建一个名为TaskTable的表,它可以具有TaskID(PK),TaskName(varchar),TaskStatus(枚举成功,失败,已调度)和TimeOfExecution。但我需要一个Windows服务,定期轮询数据库以查找任何未执行的任务。我面临的问题是:我使用什么作为TaskName保存到数据库中?班级名称?类和方法名称ToString?我怎样才能将字符串转换回来并以编程方式调用方法调用(我不希望有一个巨大的switch语句)?一项持久性的任务如下所示。所以我必须能够获得任务“SendIncompleteNotification”的名称,并将类名保存到数据库中,并以回溯方式调用
public static Task<string> SendIncompleteNotification
{
get
{
return new Task<string>
(
a => Console.WriteLine("Sample Task")
, "This is a sample task which does nothing."
);
}
}
现在的问题是我无法以原理方式保存方法/属性名称。
var type = ApplicationTask.SendIncompleteNotification.GetType();
//type.Name shows "Task`1" rather than SendIncompleteNotification
有没有更好的方法来处理这种情况?谢谢!
更新: 抱歉,我的头在旋转。我现在意识到我做错了是有另一个方法/属性来返回我的任务。我应该做的是从我的任务中获得一个新的类inhrite。在那里,我可以轻松获取类名并将字符串保存到db中,然后再退回并调用。
答案 0 :(得分:3)
您可能需要查看Windows Workflow。据我所知,它们专为长时间运行的进程而设计,可以持久保存到数据库并在事件或计时器上唤醒。
答案 1 :(得分:3)
数据库是否是必需的?
如果没有,那么Windows计划任务(他们倾向于“正常工作”)会调用一般控制台应用程序。控制台应用程序的参数可以是:
通过这种方式,您可以将所有任务放入一个或多个任务中。或者,您可以创建一个属性,将该属性应用于您的任务以为其提供“友好名称”,并对程序集使用反射来查找具有匹配属性的类。
编辑:示例:
interface ITask
{
void Execute(ExcecutionContext context);
}
[TaskName("Send Emails")
class SendEmailsTask : ITask
{
public void Execute(ExcecutionContext context)
{
// Send emails. ExecutionContext might contain a dictionary of
// key/value pairs for additional arguments needed for your task.
}
}
class TaskExecuter
{
public void ExecuteTask(string name)
{
// "name" comes from the database entry
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
// Check type.GetCustomAttributes for the TaskAttribute, then check the name
}
}
}
编辑2:这是对您的代码示例的回答。
class YourClass
{
public static Task<string> SendIncompleteNotification
{
get {
return new Task<string>(
s => Console.WriteLine("Executing task... arguments: {0}", s),
"My task");
}
}
}
interface ITask
{
void Execute(object o);
}
class Task<T> : ITask
{
public Task(Action<T> action, string name)
{
Action = action;
}
public string Name { get; set; }
public Action<T> Action { get; set; }
void ITask.Execute(object o)
{
Action((T)o);
}
}
class Program
{
static void Main(string[] args)
{
// Assume that this is what is stored in the database
var typeName = typeof (YourClass).FullName;
var propertyName = "SendIncompleteNotification";
var arguments = "some arguments";
// Execute the task
var type = Type.GetType(typeName);
var property = type.GetProperty(propertyName);
var task = (ITask)property.GetValue(null, null);
task.Execute(arguments);
Console.ReadKey();
}
}
答案 2 :(得分:1)
存储程序集FullName,并键入FullName和方法名称。假设方法签名是可预测的(如没有参数并返回void)
1)使用Assembly类型的静态LoadFrom方法创建程序集的实例。
2)使用GetType方法
从程序集中获取类类型的引用3)使用GetMethod方法从类型中获取MethodInfo实例
4)使用Activator.CreateInstance
创建该类型的实例5)使用MethodInfo实例的Invoke执行方法,从第4步传入类实例。(抱歉,我在没有VS副本的公共计算机上发出实际代码,但这5个步骤会做。
此外,如果您使用的是SQL 2005,请考虑使用SqlDependency对象,并在您的talbe更改而不是轮询时获得“通知”。
答案 3 :(得分:1)
你看过Quartz,它运作得很好,而且我很确定它会实现你需要的所有功能。