c#可靠的延迟/计划执行最佳实践

c#可靠的延迟/计划执行最佳实践,c#,scheduled-tasks,delayed-execution,C#,Scheduled Tasks,Delayed Execution,我正在从事的项目需要在特定时间执行一些任务。我不确定处理这种情况的最佳方法是什么。该方法必须能够在服务器重新启动/维护后继续使用。和方法调用必须以编程方式进行 var type = ApplicationTask.SendIncompleteNotification.GetType(); //type.Name shows "Task`1" rather than SendIncompleteNotification 我正在考虑走这条路: 我可以在数据库中有一个名为TaskTable的表(甚至

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

var type = ApplicationTask.SendIncompleteNotification.GetType();
//type.Name shows "Task`1" rather than SendIncompleteNotification
我正在考虑走这条路:

我可以在数据库中有一个名为TaskTable的表(甚至是一个消息队列),它可以有TaskID(PK)、TaskName(varchar)、TaskStatus(enum success、failed、scheduled)和Timeof Execution。但是我需要一个windows服务,它可以定期轮询数据库中任何未执行的任务。我面临的问题是:我使用什么作为任务名保存到数据库中?类名?类和方法名ToString?我如何转换回字符串并以编程方式调用方法调用(我不希望有一个巨大的switch语句)?典型任务如下所示。因此,我希望能够获得任务“SendIncompletNotification”的名称和类名,并将其保存到数据库中,然后通过编程进行检索调用

public static Task<string> SendIncompleteNotification
{
  get
    {
      return new Task<string>
        (
          a => Console.WriteLine("Sample Task")
          , "This is a sample task which does nothing."
        );
   }
}
有没有更好的方法来处理这种情况?谢谢

更新:
对不起,我头晕了。我现在意识到我做错的是使用另一个方法/属性来返回我的任务。我应该做的是从我的任务中继承一门新课。在那里,我可以很容易地获得类名并将字符串保存到db中,然后再返回并调用。

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

数据库是一种需求吗

如果没有,那么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();
    }
}
classyourclass
{
公共静态任务发送未完成通知
{
得到{
返回新任务(
s=>Console.WriteLine(“正在执行任务…参数:{0}”,s),
“我的任务”);
}
}
}
接口ITask
{
无效执行(对象o);
}
课堂任务:ITask
{        
公共任务(操作、字符串名称)
{
行动=行动;
}
公共字符串名称{get;set;}
公共操作动作{get;set;}
void ITask.Execute(对象o)
{
作用((T)o);
}
}
班级计划
{
静态void Main(字符串[]参数)
{
//假设这是存储在数据库中的内容
var typeName=typeof(YourClass).FullName;
var propertyName=“SendCompleteNotification”;
var arguments=“一些参数”;
//执行任务
var type=type.GetType(typeName);
var property=type.GetProperty(propertyName);
var task=(ITask)property.GetValue(null,null);
执行(参数);
Console.ReadKey();
}
}

存储程序集全名,然后键入全名和方法名。假设方法签名是可预测的(如无参数和返回void)

1) 使用程序集类型的静态LoadFrom方法创建程序集的实例

2) 使用GetType方法从程序集中获取对类类型的引用

3) 使用GetMethod方法从类型中获取MethodInfo实例

4) 使用Activator.CreateInstance创建类型的实例

5) 使用MethodInfo实例的调用执行该方法,从步骤4传入类实例。(很抱歉,我现在在一台公共计算机上,没有一份VS的副本来编写真正的代码,但这5个步骤就可以了


如果使用SQL 2005,请考虑使用SQLRe相依对象并获得“通知”当您的talbe更改而不是轮询时。

您看过了吗,它运行得很好,我很确定它实现了您需要的所有功能。

很抱歉,我的头脑一直在转。我现在意识到我做错了的是使用另一个方法/属性来返回我的任务。我应该做的是从我的任务中继承一个新类。并且我的继承人可以很容易地得到类名。