2012-04-24 13 views
5

Sto progettando un servizio WCF a cui tutti i miei clienti si collegheranno. Uno di questi servizi sarà un servizio di notifiche.Duplex WCF: invia notifiche diverse a ciascun client?

Vorrei che ogni client si connettesse al servizio, lo sottoscrivesse e quindi ricevesse le notifiche, utilizzando un'interfaccia di richiamata duplex (il servizio attiva l'operazione "Notifica" nei client).

Questa è la mia idea di design:

enter image description here

La mia domanda è: Quando ogni client si collega al mio servizio, mi convalidarlo contro il tavolo 'Users' nel mio database (userò un UserNamePasswordValidator e implementa la funzione 'Convalida').

Requisito: ogni utente deve ricevere notifiche diverse, in base alle regole definite nel database, ma tutte utilizzano lo stesso contratto.

Ad esempio:

John Smith s' regole nel DB potrebbe essere: Comunica su tutti i nuovi prodotti che hanno un prezzo di oltre 100 dollari.

Le regole di Jane Doe nel DB potrebbero essere: Avvisami su tutti i nuovi prodotti che i loro nomi iniziano con 'JA'.

Le regole di Jim Jabra nel DB possono essere: Avvisami su tutti i nuovi prodotti di tipo "Cibo".

Il mio servizio avrà un thread di lavoro che rileva una modifica nel database (un nuovo prodotto è stato inserito nel database).

Dovrebbe quindi eseguire il loop su tutti i client connessi e, per ciascun client, inviare una notifica del nuovo prodotto, solo se corrisponde alle richieste di notifica del client.

Ancora: tutti i client ricevono lo stesso tipo di aggiornamento (nuovi prodotti), ma ogni cliente deve ricevere prodotti diversi in base alla regola nel database.

Un approccio che ho pensato di implementare questa potrebbe essere quella di utilizzare un servizio di Singleton, che contiene un elenco di:

  • client Enpoint
  • oggetto utente (dal database)

In questo modo, ogni volta che il thread di lavoro rileva un nuovo prodotto, scorre su questo elenco e invia notifiche a chi ne ha mai bisogno. Il problema con questo approccio è che per avere un elenco globale di clienti - ho bisogno di avere il servizio come Singlton, giusto?

Il secondo approccio sarebbe ... beh ... Non ho un'altra idea di come posso accedere a un elenco di client connessi al servizio da un thread di lavoro ...

Credo che il il problema principale che ho è che ogni cliente potrebbe desiderare che generi diversi di prodotto gli vengano notificati.Significato: il metodo pub \ sub non è molto buono qui, perché il mio scenario richiede che il servizio conosca i clienti.

Qualche suggerimento su come posso risolvere questo mal di testa?

+0

Hai mai pensato di usare una coda. Dove ognuno dei tuoi client si connette alla coda e esegue il polling dei dati non appena disponibili. E semplice che il servizio WCF sia un servizio per la sottoscrizione dei dati. Quindi, nel thread di lavoro, invia i dati alla coda del client quando i dati appartengono a loro. – rpgmaker

+0

come farebbe una coda per risolvere esattamente il mio problema? cosa intendi con "il servizio wcf sarà un servizio per la sottoscrizione dei dati"? hai un campione o un esempio che posso guardare? –

+0

La mia risposta è inferiore a – rpgmaker

risposta

2

In qualsiasi modo con la comunicazione duplex, è necessario mantenere il canale TCP aperto da server a client per poter inviare notifiche.

Il client è colui che avvia la connessione al server, e è necessario mantenere questa connessione aperta, se questa connessione viene persa non è possibile (non dovrebbe) avviare la connessione dal server al client, perché il client può essere dietro NAT , avere un firewall, ecc.

Quindi in ogni caso deve esserci qualche oggetto statico (singleton) sul lato server che mantiene l'elenco delle connessioni dei client, pensavo che questo non sia necessariamente un servizio WCF. La dipendenza può iniettare questo oggetto nel costruttore di servizi.

public class ProductRepository 
{ 
    private EventAggregator eventAggregator; 

    public void Add(Product product) 
    { 
     //... 
     eventAggregator.Publish(new NewProductEvent(product)) 
    } 
} 
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] 
public class EventPublishingService 
{ 
    private IClientCallback client; 
    private EventAggregator eventAggregator; 
    private Func<Product, bool> predicate; 

    public EventPublishingService(...) 
    { 
     eventAggregator.Subscibe<NewProductEvent>(OnNewProduct); 
    } 
    private void OnNewProduct(NewProductEvent e) 
    { 
     if (predicate(e.Product)==true) client.Notify(e.Product); 
    } 

    public void Subscribe() 
    { 
     client = OperationContext.Current.GetCallbackChannel<IClientCallback>() 
     var user = ServiceSecurityContext.PrimaryIdentity; 
     predicate = GetFilterForUser(user); 
    } 
} 
+0

Quindi stai dicendo che ho bisogno di un servizio Singleton e di iniettare il thread di background worker al servizio nel suo costruttore? Non dovrei fare il contrario? Inietti il ​​servizio nel costruttore del lavoratore in background? –

+0

@JohnMiner, non sono sicuro di quello che ti serve. Ho scritto un piccolo esempio. –

+0

wow, grazie per l'ampio esempio! Cercherò di spiegare perché ho bisogno di un thread di lavoro. C'è una tabella nel database che contiene le regole per ciascun utente - quali prodotti desidera. USER1 ha una regola che dice di voler essere avvisato dei prodotti con "prezzo> 50". USER2 ha una regola che dice di voler essere avvisato dei prodotti con "prezzo> 30 e prezzo <70". USER3 ha una regola che dice che vuole prodotti con "FOOD" nel loro nome. continua nel prossimo commento –

0

Quello che intendevo dire è il seguente.

Creare un servizio wcf che verrà chiamato da ciascun client per la sottoscrizione ai filtri una volta. Il servizio wcf stesso aggiungerà semplicemente dati al database e includerà informazioni come il nome del cliente e le informazioni sui filtri nell'archivio dati. Quindi il tuo thread di lavoro che sarà in un servizio di finestra che semplicemente eseguirà il polling del tuo database per i dati e quando i dati saranno disponibili leggerà dalle tabelle di abbonamento. Quindi invierà i dati alla coda di ciascun client che potrebbe essere un queue server condiviso come rabbitmq.

Dal lato client assumendo che si tratti di un'applicazione basata su finestra, verrà semplicemente eseguito il polling del server di coda di rabbitmq per i dati cercandolo nella coda con il nome di se stesso (client1, e.t.c).

Problemi correlati