3

我正在进行的项目需要在特定时间完成一些执行。我不确定处理这种情况的最佳方法是什么。该方法必须能够在服务器重新启动/维护后继续存在。并且方法调用必须以编程方式进行。

我正在考虑走这条路:

我可以在数据库(甚至是消息队列)中有一个名为 TaskTable 的表,它可以有 TaskID(PK)、TaskName(varchar)、TaskStatus(enum success、failed、scheduled) 和 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

有没有更好的方法来处理这种情况?谢谢!

更新:对不起,我的头在旋转。我现在意识到我做错了什么是有另一种方法/属性来返回我的任务。我应该做的是从我的任务中继承一个新的类。在那里我可以轻松地获取类名并将字符串保存到数据库中,然后再返回并调用。

4

4 回答 4

3

您可能想查看 Windows 工作流。据我所知,它们是为长时间运行的进程而设计的,可以持久化到数据库并在事件或计时器上唤醒。

于 2009-03-26T03:27:49.773 回答
3

数据库是必需的吗?

如果不是,那么调用通用控制台应用程序的 Windows 计划任务(他们倾向于“正常工作”)呢?控制台应用程序的参数可能是:

  • 包含要执行的任务的 DLL
  • 实现您定义的接口的类的名称
  • 其他论点

这样,您可以将所有任务放入一个程序集或多个程序集中。或者,您可以创建一个属性,将该属性应用到您的任务以给它们一个“友好的名称”,然后对程序集使用反射来查找具有匹配属性的类。

编辑:示例:

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();
    }
}
于 2009-03-26T03:29:09.643 回答
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 更改而不是轮询时获得“通知”。

于 2009-03-26T03:31:15.130 回答
1

你看过Quartz吗,它工作得很好,而且我很确定它实现了你需要的所有功能。

于 2009-03-26T03:37:12.260 回答