Domanda

Il progetto cui sto lavorando richiede alcune esecuzioni da fare in un determinato momento. Non sono sicuro di quello che sarebbe il modo migliore per affrontare questa situazione. Il metodo deve essere in grado di sopravvivere riavvio del server / manutenzione. E le chiamate di metodo devono essere a livello di codice.

Sto considerando percorrere questa strada:

ho potuto avere una tabella nel database (o anche una coda di messaggi) chiamato TaskTable che potrebbe avere TaskID (PK), TaskName (varchar), TaskStatus (successo enum, non è riuscito, in programma) e TimeOfExecution. Ma ho bisogno di un servizio di Windows che interroga periodicamente il database per qualsiasi attività non eseguiti. Problema che sto affrontando è che: Cosa posso usare come TaskName per salvare nel database? Nome della classe? di classe e nome del metodo ToString? E come posso convertire la stringa indietro e di programmazione invocare le chiamate di metodo (che non vogliono avere un'istruzione switch gigante)? Un compito typtical sarà simile di seguito. Così ho ned essere in grado di ottenere il nome del compito "SendIncompleteNotification" e il nome della classe Salva in database e 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."
        );
   }
}

Il problema ora è che sto avendo problemi di salvare il nome del metodo / proprietà progrmatically.

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

V'è alcuna modi migliori di affrontare questa situazione? Grazie!

Aggiornamento: Spiacente mi girava la testa. ciò che ora sono reso conto che ho fatto di sbagliato era quello di avere un altro metodo / proprietà per restituire il mio compito. Cosa avrei dovuto fare era di avere una nuova classe da inhrite mio compito. E ci posso facilmente ottenere il nome della classe e salvare la stringa in db e poi retireve indietro e richiamare.

È stato utile?

Soluzione

è il database un requisito?

In caso contrario, che dire di un'attività pianificata di Windows (che hanno una tendenza a "solo lavoro"), che chiede in una console app generale. Gli argomenti della console app potrebbero essere:

  • Una DLL che contiene il compito di eseguire
  • Il nome di una classe che implementa l'interfaccia si definisce
  • Altri argomenti

In questo modo è possibile inserire tutte le attività in un unico gruppo, o multipla. In alternativa è possibile creare un attributo, applicare tale attributo per le attività per dare loro un "nome descrittivo", e utilizzare la riflessione sopra il gruppo per trovare le classi con l'attributo di corrispondenza.

Modifica: esempio:

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

Modifica 2: Questo è in risposta alla tua di codice

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

Altri suggerimenti

Si potrebbe voler guardare in Windows Workflow. Essi sono progettati per i processi di esecuzione prolungata, può essere persistevano a un database e svegliati sull'evento o il timer, per quanto ne so.

Conservare il FullName assemblaggio e digitare FullName e il nome del metodo. Supponendo che la firma del metodo è qualcosa di prevedibile (come parametri e vuoto ritorno)

1) creare un'istanza del complesso con il metodo LoadFrom statico del tipo Assembly.

2) ottenere un riferimento al tipo di classe dalla vostra assemblea con il metodo GetType

3) ottenere MethodInfo esempio dal tipo utilizzando il metodo GetMethod

4) creare un'istanza del tipo utilizzante Activator.CreateInstance

5) eseguire il metodo che utilizza l'Invoke dell'istanza MethodInfo, passando l'istanza della classe dal punto 4. (mi dispiace che io sono in un computer pubblico senza una copia di VS per sfornare il codice vero e proprio, ma quei 5 passi sarebbe fare.

Anche se si sta utilizzando SQL 2005 considerare l'utilizzo di un oggetto SqlDependency e ottenere "notificato" quando le modifiche talbe piuttosto che di polling.

Hai guardato quarzo , funziona piuttosto bene, e sono abbastanza sicuro che implementa tutte le funzioni necessarie.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top