Domanda

  • Ho un'applicazione di servizio Windows in cui creo servizi WCF.
  • Uno dei servizi sono i servizi dati: aggiungi, elimina, leggi, dati UPDATTE tramite WCF.
  • WCF Utilizzare NHibernate per la manipolazione dei dati

Quindi le mie ospiti sono:

  • Qualche consiglio (Best Practice) per la gestione delle sessioni per Hibernate utilizzando con WCF?

  • Qualcuno sa qualcosa di cui

WcfoperationessionContext (Classe Hibernate 3.0)?

how to use it with WCF?

Bene, per renderlo concreto:

Supponiamo di aver chiamato il servizio WCF Servizi dati

class WCFDataService .....
{

   void SaveMyEntity(MyEntity entity)
    {



         .....................?? // How to do? Best Way

         // Should i take one session  and use it all times
         // Should i take session and dipsose when operation finished then get 
         //new session for new operations?
         // If many clients call my WCF service function at the same time?
         // what may go wrong?
         // etc....


     }


 }

E ho bisogno di un NhibernateServiceProvider classe

class NHibernateServiceProvider ....
{

    // How to get Session ?? Best way

     ISession GetCurrentSession(){.... }
     DisposeSession(){ ....}
}

Auguri

PS: ho letto voci simili qui e altre pagine Web. Ma non riesco a vedere le risposte "concrete".

È stato utile?

Soluzione

Ecco un inviare descrivendo, in dettaglio, tutti i passaggi per la registrazione e l'utilizzo di WCFoperationSessionContext. Include anche istruzioni per l'utilizzo con il progetto Agatha-RRSL.

Altri suggerimenti

WCFOPERATISESSESSEXCONTEXT, simile a ThreadStaticesssionContext e WebRequestSessionContext è un'implementazione per un contesto di sessione. Il contesto della sessione viene utilizzato per vincolare (associare) un'istanza di ISession in un particolare contesto.

La sessione nel contesto attuale può essere recuperata chiamando ISessionFactory.getCurrensession ().

Puoi trovare maggiori informazioni su contesto di sessione qui.

WCFOPERATISESSESSEXCONTEXT rappresenta un contesto che si estende per l'intera durata di un'operazione WCF. È ancora necessario gestire l'associazione della sessione nell'inizio dell'operazione e l'indennità/commedi/smaltimento della sessione al termine dell'operazione.

Per ottenere l'accesso alle azioni di inizio/fine nella pipeline WCF è necessario implementare un IdisPatchMessageIsctor. Puoi vedere un campione qui.

Anche per quanto riguarda l'integrazione WCF: se si utilizza il contesto della sessione ThreadStatic, sembrerà funzionare sullo sviluppo, ma colpirai il muro in produzione quando vari componenti (Ex: Autorizzazione, autenticazione) dalla pipeline WCF vengono eseguiti su diversi thread.

Per quanto riguarda le migliori pratiche che l'hai quasi inchiodato: usa WCFoperationSessionContext per archiviare la sessione corrente e l'IdisPatchMessageInspector per iniziare/completare la tua unità di lavoro.

Modifica: per affrontare i dettagli che hai aggiunto: Se hai configurato WCFoperationSessionContext e esegui il legame/senza fine come ho spiegato sopra, tutto ciò che devi fare è iniettare ilFactory nel tuo servizio e utilizzare Factory.GetCurrensession (). Pubblicherò un PRJ di esempio se il tempo lo consente.

Ecco il Progetto di esempio

Il modello che utilizziamo per la gestione delle sessioni di nhibernate con WCF è il seguente:

1) Abbiamo la nostra classe ServiceHost che eredita da System.ServiceModel.ServiceHost che implementa anche IcallContextInitializer. Aggiungiamo l'istanza dell'host di servizio a ciascuna delle operazioni del nostro servizio come segue:

protected override void InitializeRuntime()
{
    base.InitializeRuntime();
    foreach (ChannelDispatcher cd in this.ChannelDispatchers)
    {
        foreach (EndpointDispatcher ed in cd.Endpoints)
        {
            foreach (DispatchOperation op in ed.DispatchRuntime.Operations)
            {
                op.CallContextInitializers.Add(this);
             }
        }
    }
}

public void AfterInvoke(object correlationState)
{
    // We don't do anything after the invoke
}

public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
    OperationContext.Current.Extensions.Add(new SessionOperationContext());
    return null;
}

Il prima invoke si assicura semplicemente che OperationContext per ogni chiamata WCF abbia la sua sessione. Abbiamo riscontrato problemi con IdisPatchMessageInspector in cui la sessione non è disponibile durante la serializzazione della risposta, un problema se si utilizza un caricamento pigro.

2) Il nostrocontext SessionOperation verrà quindi chiamato per allegare se stesso e utilizziamo l'evento operativo completo per rimuoverci. In questo modo possiamo essere sicuri che la sessione sarà disponibile per la serializzazione di risposta.

public class SessionOperationContext : IExtension<OperationContext>
{

    public ISession Session { get; private set; }

    public static SessionOperationContext Current
    {
        get
        {
            OperationContext oc = OperationContext.Current;
            if (oc == null) throw new InvalidOperationException("Must be in an operation context.");
            return oc.Extensions.Find<SessionOperationContext>();
        }
    }

    public void Attach(OperationContext owner)
    {
        // Create the session and do anything else you required
        this.Session = ... // Whatever instantiation method you use

        // Hook into the OperationCompleted event which will be raised
        // after the operation has completed and the response serialised.
        owner.OperationCompleted += new EventHandler(OperationCompleted);
    }

    void OperationCompleted(object sender, EventArgs e)
    {
        // Tell WCF this extension is done
        ((OperationContext)sender).Extensions.Remove(this);
    }

    public void Detach(OperationContext owner)
    {
        // Close our session, do any cleanup, even auto commit 
        // transactions if required.
        this.Session.Dispose();
        this.Session = null;
    }
}

Abbiamo usato con successo il modello sopra in applicazioni ad alto carico e sembra funzionare bene.

In sintesi, questo è simile a quello che fa la nuova WCFoperationSessionContext (non era in circolazione quando abbiamo capito il modello sopra ;-)) ma supera anche i problemi relativi al caricamento pigro.

Per quanto riguarda le domande aggiuntive poste: Se usi il modello descritto sopra, faresti semplicemente quanto segue:

void SaveMyEntity(MyEntity entity)
{
    SessionOperationContext.Current.Session.Save(entity);
}

È garantito che la sessione è sempre lì e che verrà eliminata una volta completata l'operazione WCF. È possibile utilizzare le transazioni se necessario in modo normale.

OK, dopo alcuni giorni di lettura di post su Internet ecc. Tutti gli approcci mostrati negli Internet sembrano essere sbagliati. Quando stiamo usando il modello di unità di lavoro con NH 3^ con transazione nhibernate, tutti gli APROCHAE stanno producendo eccezioni. Per testarlo e provare che dobbiamo creare un ambiente di prova con la coda di transazioni MSMQ, interfaccia speciale con contratto operativo di Oneway con transazione richiesto su di esso. Questo approccio dovrebbe funzionare in questo modo: 1. Mettiamo in coda un messaggio in coda. 2. Il servizio sta ottenendo messe in coda transazionale. 3. Tutto funziona in coda è vuota.

In alcuni casi non così oboso con gli approcci Internet, questo non funziona correttamente. Quindi qui ci sono espamsioni che abbiamo testato che sono sbagliati e perché:

  1. Approccio Fabio Maulo: usa IcallContextInitializer - Apri NH Session/Transaction su BeForeCall, dopo che WCF sta eseguendo il metodo di servizio, su AfterCall in Context Initializer We Call Session.flush + Transaction.Commit. La sessione automatica verrà salvata quando l'ambito delle transazioni commetterà il funzionamento. In situazione in cui su Calling Transaction Transaction Eccezione verrà lanciata il servizio WCF si spegne! La domanda può essere ok, quindi prendi la transazione.complete in Try/Catch Clausule - Fantastico! - Niente sbagliato! Quindi l'ambito delle transazioni commetterà transazione e il messaggio verrà preso dalla coda ma i dati non verranno salvati!
  2. Un altro approccio è quello di utilizzare IdisPatchMessageIspector - ieri ho pensato che questo fosse il miglior approccio. Qui dobbiamo aprire sessioni/transazioni nel metodo AfterReceiveRequest, dopo che viene chiamato l'operazione di servizio WCF sull'ispettore di dispatcher di messaggi prima di fare. In questo metodo abbiamo informazioni su [Risposta] che nell'operazione di Oneway è nullo, ma riempita di informazioni sui guasti se si è verificato con il metodo di servizio invocazione. Fantastico ho pensato - questo è questo! ma no! Il problema è che a questo punto nel tubo di elaborazione WCF non abbiamo transazioni! Quindi, se Transaction.complete Errore di lancio o session.flush lo lancerà, non avremo i dati salvati nel database e il messaggio non tornerà in coda ciò che è sbagliato.

Qual'è la soluzione?

Ioperationinvoker E solo questo!

È necessario implementare questa interfaccia come motivo decoratore su Invocatore predefinito. In Method invochy PRIMA CHIAMA CHE CHE APERTI APERTURE SESSIONE/TRANSAZIONE Quindi chiamiamo Invochy Default Invocatore e, dopo quella chiamata Call Transaction.Compreate in Clausule, chiamiamo session.flush. Quali tipi di problema questo risolve: 1. Abbiamo un ambito di transazione a questo livello, quindi quando il completamento lancia un messaggio di eccezione tornerà in coda e WCF non si interromperà. 2. Quando l'invocazione lancerà la transazione di eccezione.Complete non verrà chiamato ciò che non cambierà lo stato del database

Spero che questo chiarisca la pessima formazione di tutti.

In un po 'di tempo libero proverò a scrivere qualche esempio.

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