2013-05-08 4 views
1

appel d'une fonction seulement après un certain intervalle de temps, bien que l'utilisateur final fait une demandeContrôler l'appel de fonction par minuterie C#

public override void SendNotificationMessage(NotificationMessageRequest request) 
    {......} 

c'est ma fonction qui sera déclenchée quand il y a une action de clic.

Je veux que cela soit appelé seulement à certains intervalles de temps disons 5 mins.Although l'utilisateur fait une demande avant l'intervalle de temps ...

Je suis en train d'avoir une minuterie pour servir mon but, mais le problème est à chaque fois que l'utilisateur clique alors minuterie commencerait again..so que la façon dont une fonction peut être contrôlée par minuterie

PS: Je ne peux pas faire des changements dans l'application utilisateur où le clic est fait

+0

Pourriez-vous poster plus d'exemple de code pour SO à déchiffrer? – Sean

+0

Avez-vous plusieurs utilisateurs qui peuvent appeler cette fonction dans votre application? – ppetrov

+0

oui il y aura plusieurs utilisateurs et une fois cette fonction est appelée, il y aura une notification envoyer à d'autres .... donc pour éviter le spam je cherche l'appel en temps opportun de cette fonction – Raghu

Répondre

1

en tant que solution rapide Je peux suggérer de garder une liste de délégués avec la méthode que vous voulez invoquer à chaque coche de minuterie. Donc, sur l'action de l'utilisateur, vous ajoutez simplement la méthode que vous voulez appeler. Si les paramètres doivent être uniques pour chaque appel d'utilisateur, vous pourriez faire quelque chose comme dans le code suivant:

// This is the class handling the timer ticks 
public class ActionExecutor : IDisposable 
{ 
    private Timer timer; 

    private IList<Action> actionsList = new List<Action>(); 

    public ActionExecutor() 
    { 
     // choose the interval as suits you best, or use 
     // constructor argument 
     timer = new Timer(1000); 
     timer.Elapsed += OnTimerTick; 
     timer.AutoReset = true; 
     timer.Start(); 
    } 

    void OnTimerTick(object sender, ElapsedEventArgs) 
    { 
     lock(actionsList) 
     { 
      foreach(Action a in actionsList) 
      { 
       a(); 
      } 
      actionsList.Clear(); 
     } 
    } 

    public void AddAction(Action a) 
    { 
     lock(actionList) 
     { 
      actionList.Add(a); 
     } 
    } 

    public void Dispose() 
    { 
     // we must stop the timer when we are over 
     if (timer != null) 
     { 
      timer.Stop(); 
     } 
     if (actionList != null) 
     { 
      actionList.Clear(); 
     } 
    } 
    ~ActionExecutor() 
    { 
     Dispose(); 
    } 
} 

//handling user click in your application 

void OnUserClick() 
{ 
    // built the specific notification request 
    NotificationMessageRequest request = ... 

    actionExecutor.AddAction(() => SendNotificationMessage(request)); 
} 

Dans le code ci-dessus, vous devez vous assurer que vous utilisez le même ActionExecutor instance où vous gérez les actions de l'utilisateur. Notez la synchronisation avec les verrous - les temporisateurs s'exécutent généralement dans un thread distinct de celui qui ajoute l'action. Si vous parlez d'une application Web, chaque utilisateur exécute son propre thread, de sorte que plusieurs utilisateurs à la fois ajoutent également la concurrence. En outre, vous devrez peut-être ajouter une gestion des erreurs appropriée, car j'ai omis cette partie par souci de concision.


Mise à jour

Comme suggéré dans les commentaires, vous pouvez bénéficier d'utiliser une collection différente de celle d'une liste pour tenir les actions. Cela dépend des besoins réels de votre scénario.

+0

Je ne pense pas une 'List' de' Action' suffira, ce devrait être un 'Dictionnary' ou autre chose basé sur un userId. Sinon, un utilisateur peut planifier plusieurs exécutions de la même action sans le remarquer – ppetrov

+0

@ppetrov Oui, cela pourrait être une meilleure approche si le PO veut éviter la duplication ou gérer autrement les éléments ajoutés. J'ai choisi 'List' pour autoriser l'exécution des actions dans l'ordre ajouté. –

+0

Cela ne résout pas à mon cas puisque chaque fois que le bouton est cliqué, la même fonction est appelée et à cette fonction j'ai besoin d'une minuterie et votre code peut être utilisé seulement quand il y a beaucoup de fonctions – Raghu

0

Je fais quelque chose de similaire dans mon système actuel. Dans mon cas, je traite des demandes de données de manière à ce que plutôt que de faire plusieurs appels à un service distant, je peux les combiner en un seul.

Ceci est un aperçu de haut niveau du système:

J'ai un CollatorClass qui a une méthode makeRequest() interne, CollatorClass a un objet Timer qui est initalised à null et une liste de tous les objets qui tiennent votre détails de la demande.

Lorsque MakeRequest est appelé: Le temporisateur est démarré s'il est nul. Les détails de la demande sont ajoutés à une liste.

Lorsque la minuterie est terminée, le système lit les détails de toutes les demandes de la liste et prend les mesures appropriées. (Notez que vous devrez peut-être utiliser le verrou pour rendre tout ce thread sûr).

Si vous le souhaitez, vous pouvez également passer une référence d'action à appeler lorsque la demande de données est réellement effectuée. Je ne sais pas si c'est nécessaire dans votre cas. Faites-moi savoir si vous souhaitez plus de détails.

+0

Je ne vais pas faire la demande par lots ... Je vais bloquer la demande et donc seuls les appels en temps opportun seront mis en œuvre et d'autres ne seront pas exécutés du tout – Raghu

+0

Vous pouvez l'appliquer simplement en changeant la méthode MakeRequest pour ajouter seulement une requête à la liste si la temporisation était nulle. (oh et n'oubliez pas d'annuler l'objet timer à la fin de la méthode tick tick.) – Steve

1

D'abord, vous devez ajouter un Dictionnary à votre classe:

Dictionnary<int, NotificationMessageRequest> _notifications 

Ensuite, lorsqu'un utilisateur clique sur le bouton, vous devez exécuter cette fonction: (ou changer celui qui est exécuté maintenant pour que ça ressemble à ça)

private void PlanNotification(NotificationMessageRequest request, int userId) 
{ 
    // or grab the userId from where you can 
    lock(_notifications) // if needed ? 
    { 
     if (_notifications.Contains(userId)) return; 

     _notifications.Add(userId, request); 
    } 
} 

appeler cette méthode sur votre événement timer:

private void SendNotifications() 
{ 
    lock(_notifications) 
    { 
     foreach(KeyValuePair<int, NotificationMessageRequest> p in _notifications) 
      SendNotificationMessage(p.Value); 

     _notifications.Clear(); 
    } 
} 

Si y Si vous faites quelque chose de plus ou moins comme ça, vous aurez le comportement dont vous avez besoin.

+0

permettez-moi de le faire pour un seul utilisateur ... je suis un utilisateur unique et il peut faire plusieurs demandes..Premier let Je le résoudre et à l'avenir, il peut y avoir des chances d'utilisateurs multiples ... appels simples onClick() et donc la fonction exécute une fois et maintenant même s'il appelle onClick() à nouveau la fonction ne devrait pas être appelée – Raghu

+1

Cela fonctionnera pour tous les utilisateurs vouloir. Mais de cette façon, votre fonction ne sera exécutée que toutes les cinq minutes (par exemple). Si l'utilisateur clique sur le bouton et que le temporisateur n'a pas encore coché, il exécutera la fonction plus tard. – ppetrov

+0

+1 ayant la collection de 'NotificationMessageRequest' est une approche plus facile et probablement meilleure pour le cas de l'OP. –

0

Créez une minuterie et réglez son intervalle sur une valeur correcte. Puis déclarez un champ de type System.Collections.Concurrent.ConcurrentQueue<YourMessageType> (statique si cela vous convient) et placez votre message dans la file d'attente du OnClick.

Lorsque la touche de temporisation appelle TryDequeue et traite les messages.

+0

oui j'ai essayé mais à chaque fois que le onClick() est appelé et donc la minuterie est redémarrée .. donc mon but de bloquer une fonction ne sera pas servi – Raghu

+0

Pourquoi le minuteur devrait être redémarré? Si c'est une application web, faites-en un champ statique (et évidemment votre gestionnaire de tic-tac serait aussi statique). Créez-vous le minuteur chaque fois que OnClick est appelé? –

+0

non je crée une minuterie pour chaque onClick mais je ne suis pas sûr de la façon d'implémenter un champ de minuteur statique 'Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); // logique métier ...stopWatch.Stop(); int timer = (int) stopWatch.ElapsedMilliseconds; ' maintenant la variable de temporisation a une certaine valeur et en fonction de la valeur, la prochaine requête doit être bloquée (<5000) ou autorisée (> 5000) – Raghu