Question

Le projet sur lequel je travaille exige des exécutions à faire à un certain moment. Je ne sais pas quelle serait la meilleure façon de faire face à cette situation. La méthode doit être en mesure de survivre serveur redémarrage / maintenance. Et les appels de méthode doivent être un programme.

J'envisage d'aller dans cette voie:

Je pourrais avoir une table dans la base de données (ou même une file d'attente de messages) appelé TaskTable qui pourrait avoir TaskID (PK), TaskName (varchar), TaskStatus (de succès ENUM, a échoué, prévu) et TimeOfExecution. Mais je besoin d'un service Windows qui interroge régulièrement la base de données pour toutes les tâches non exécutées. Problème Je suis face est que: Que dois-je utiliser comme TaskName pour enregistrer dans la base de données? Nom du cours? classe et nom de la méthode ToString? Et comment puis-je convertir la chaîne en arrière et appeler par programme les appels de méthode (je ne veux pas avoir une instruction switch géant)? Une tâche typtical ressemblerait ci-dessous. Donc, je ned être en mesure d'obtenir le nom de la tâche « SendIncompleteNotification » et le nom de classe l'enregistrer dans la base de données et sur Invoke retrival programatically

public static Task<string> SendIncompleteNotification
{
  get
    {
      return new Task<string>
        (
          a => Console.WriteLine("Sample Task")
          , "This is a sample task which does nothing."
        );
   }
}

Le problème est maintenant j'ai problème sauver la méthode / nom de la propriété progrmatically.

var type = ApplicationTask.SendIncompleteNotification.GetType();
//type.Name shows "Task`1" rather than SendIncompleteNotification

Y at-il de meilleures façons de faire face à cette situation? Merci!

Mise à jour: Désolé ma tête tournait. Je réalise maintenant ce que j'ai eu tort était d'avoir une autre méthode / propriété pour retourner ma tâche. Ce que je aurais dû faire était d'avoir une nouvelle inhrite de classe de ma tâche. Et là, je peux facilement obtenir le nom de classe et de mettre la chaîne en db et retireve plus tard en arrière et invoquer.

Était-ce utile?

La solution

est la base de données une exigence?

Dans le cas contraire, qu'en est une tâche planifiée Windows (ils ont une tendance à « juste travail ») qui remet en une application console générale. Les arguments à l'application de la console pourrait être:

  • Une DLL contenant la tâche à exécuter
  • Le nom d'une classe qui implémente une interface que vous définissez
  • D'autres arguments

De cette façon, vous pouvez mettre toutes vos tâches dans un ensemble, ou multiple. Sinon, vous pouvez créer un attribut, appliquer cet attribut à vos tâches pour leur donner un « nom convivial », et utiliser la réflexion sur l'ensemble de trouver des classes avec l'attribut correspondant.

Edit: par exemple:

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
        }
    }
}

Edit 2: Ceci est en réponse à votre exemple de code

.
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();
    }
}

Autres conseils

Vous pouvez regarder dans Windows Workflow. Ils sont conçus pour une longue processus en cours, peuvent être conservées à une base de données et réveillées sur l'événement ou d'une minuterie, pour autant que je sache.

Rangez le FullName de montage et tapez FullName et le nom de la méthode. En supposant que la signature de la méthode est quelque chose prévisible (comme aucun paramètre et sans effet de retour)

1) créer une instance de l'ensemble en utilisant la méthode LoadFrom statique du type d'assemblage.

2) obtenir une référence au type de classe de votre assemblage en utilisant la méthode GetType

3) obtenir instance MethodInfo du type utilisant la méthode GetMethod

4) créer une instance du type utilisant Activator.CreateInstance

5) exécuter la méthode en utilisant Invoke de l'instance MethodInfo, en passant dans l'instance de classe de l'étape 4. (désolé que je suis à un ordinateur public sans une copie de VS à manivelle vrai code mais ces 5 mesures prendriez faire.

Aussi, si vous utilisez SQL 2005 envisager d'utiliser un objet SqlDependency et obtenir « informé » lors de vos changements de Talbe plutôt que l'interrogation.

Avez-vous regardé Quartz , cela fonctionne assez bien, et je suis sûr qu'il met en œuvre tous les fonctionnalités dont vous avez besoin.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top