6

Recentemente abbiamo avuto alcune occasioni in cui è venuta la domanda se in Dynamics CRM 2011, un'esecuzione di plug-in (vale a dire un passaggio del metodo Execute()) è garantita per rimanere sullo stesso thread.Threading/Ambient Context nei plugin CRM 2011

Vorrei implementare la traccia utilizzando il modello Ambient Context per evitare di passare il servizio di tracciamento a qualsiasi classe che potrebbe voler tracciare. Il problema è che, come sappiamo, il plugin viene istanziato una sola volta per ogni passo registrato e quindi serve tutte le operazioni successive dalla stessa istanza; ciò significa che non posso avere solo alcune proprietà statiche come Tracing.Current a cui assegno l'istanza attuale ITracingService e sono a posto. Se lo facessi, l'operazione avviata per ultima sovrascriverebbe l'istanza per tutte le altre operazioni che potrebbero ancora essere in esecuzione (e questo tipo di concorrenza non è raro).

Ora, se potessi essere sicuro che tutto sotto il metodo Execute() rimane nello stesso thread, ho potuto ancora utilizzare un contesto ambientale che utilizza l'attributo [ThreadStatic] per i campi statici:

public static class Tracing 
{ 
    [ThreadStatic] 
    private static ITracingService _current; 

    public static ITracingService Current 
    { 
     get 
     { 
      if (null == _current) 
      { 
       _current = new NullTracingService(); 
      } 

      return _current; 
     } 

     set { _current = value; } 
    } 
} 

vorrei impostare questo entrando nella Execute() e cancellarlo alla fine in modo da rimuovere il riferimento all'istanza del servizio di traccia.

L'unica cosa che potrei tipo di trovare informazioni sul threading nel contesto dei plugin MSCRM è che apparentemente i singoli thread provengono dal ThreadPool - qualsiasi conseguenza che potrebbe avere riguardo al mio problema.

Qualcuno ha una conoscenza più approfondita di come viene gestito il threading con i plug-in MSCRM o di altre idee su come la preoccupazione trasversale della traccia possa essere gestita elegantemente con il codice SOLID in questo caso speciale (AOP/intercettazione dinamica no opzioni qui)?

Grazie per qualsiasi aiuto e indicazioni.

+0

Capisco la tua preoccupazione per l'esecuzione in un thread sicuro, ma non sono sicuro di capire perché sei preoccupato di correre sullo stesso thread. Puoi spiegare un po 'di più? – Daryl

+0

Bene, avrei bisogno di evitare che l'esecuzione del plugin venisse spostata su un altro thread senza che la sua istanza ITracingService fosse "collegata" di nuovo. Non sono ancora riuscito a scoprire come sarebbe stata gestita la cosa ThreadStatic in questo caso. – TeaDrivenDev

risposta

3

La risposta semplice e intelligente: se fa male quando lo fai, allora non farlo. :)

Il requisito che impone l'utilizzo del pattern Ambient Context è in conflitto con il modello di progettazione di CRM. Pensa a come funziona il CRM: ti passa uno IServiceProvider, con tutto il necessario, compreso il servizio di tracciamento. Gestisce tutto il complicato multithreading e le ottimizzazioni per te, e ti chiede solo di non provare a superarlo in astuzia con schemi di fantasia o variabili statiche o trucchi di threading.

La mia raccomandazione è quella di utilizzare lo stesso modello: passare lo IServiceProvider a qualsiasi classe o metodo che ne ha bisogno. Molto più semplice - e più tardi quando hai un bug strano, non ti chiederai se sei riuscito a superare in astuzia gli ingegneri di Microsoft o meno. :)

+0

Sono d'accordo sul fatto che si dovrebbe sempre essere cauti nel prendere le cose troppo lontano o usare i sistemi in un modo in cui non sono stati progettati per essere usati. Non riesco a vedere come ci sarebbe un "complicato multithreading" coinvolto nel servizio di tracciamento, però. Ci sarà o non lo sarà, e quello che sto cercando è un modo per assicurarmi che lo sia. ;-) A proposito, il requisito autoimposto è in realtà un buon progetto software gestibile. The Ambient Context è solo un mezzo per un fine, e sarei felice di farne a meno, se possibile. – TeaDrivenDev

+0

E 'solo così puoi scrivere Tracing.Current invece di scrivere il codice per estrarre il servizio Tracing da IServiceProvider ogni volta? Se è così, forse guarda scrivere un metodo di estensione C# sull'oggetto ServiceProvider che ottiene facilmente un riferimento al servizio di Tracciamento. Oppure usa uno snippet di codice che incolla il codice di default per te: non cambierà probabilmente, e se lo fa, è un semplice trovare/sostituire. Soprattutto, non spendere più di altri 10 minuti su di esso e iniziare a risolvere problemi di business reali, amico! Sono felice di non averti pagato per preoccuparti di questo! :) –

0

Temo di poter solo intuire l'intero problema di plug-in/thread/static qui, tuttavia ciò che si propone sembra un po 'complicato. Quindi, in alternativa, hai preso in considerazione l'utilizzo di Trace Listener?

Se si utilizza Trace.Writeline attraverso l'applicazione, un singolo Listener di traccia acquisisce tutti quei messaggi. In questo modo non devi passare un oggetto traccia in giro.

Ad esempio:

Execute(...) 
{ 
    if(System.Diagnostics.Trace.Listeners 
     .Count(l => typeof(l) == MyCustomTraceListener) == 0) 
    { 
     System.Diagnostics.Trace.Listeners.Add(new MyCustomTraceListener()); 
    } 

    DoWork(); 
} 

DoWork() 
{ 
    System.Diagnostics.Trace.WriteLine("I'm doing work!"); 
} 

link pertinenti:

Trace Listeners e Walkthrough: Creating a Custom Trace Listener

+0

Ho letto di loro, ma li ho respinti a titolo definitivo. Prendo quelli che sono registrati per l'intero processo/AppDomain, giusto? Ogni chiamata a 'Execute()' sulla stessa istanza del plugin porta con sé la propria istanza ITracingService e deve essere garantita per utilizzare esattamente e solo quell'istanza. Quello che sto cercando è un modo per garantire che senza inquinare la maggior parte dei miei costruttori con un parametro che non è effettivamente richiesto per la rispettiva classe di fare il suo lavoro. – TeaDrivenDev

+0

Non so in cima alla mia testa, dovrei scavare intorno al MSDN. Capisco la tua situazione Sono stato lì io a passare in giro oggetti di registrazione tutte le mie funzioni e classi. Avrò una riflessione sul processo/bit di AppDomain. –

0

CRM crea un singolo oggetto plug-in, e quindi utilizza le discussioni sono necessarie per elaborare le richieste. Quindi l'unica cosa di cui puoi essere sicuro è che avrai più thread in esecuzione in un singolo momento per un singolo oggetto plugin.

I thread sono gestiti tramite IIS e verranno riutilizzati, se possibile. Quindi, se vuoi assicurarti che ogni volta che si chiami Execute, abbia un nuovo ITracingService, dovrai impostarlo. Se vuoi solo assicurarti che ogni volta che si chiami Execute, ne abbia uno, devi solo eseguire una dichiarazione if per verificarlo.

Poiché la variabile di backup è ThreadStatic, non è necessario preoccuparsi dei problemi di threading, ma poiché IIS tenta di riutilizzare i thread, non sarà vuoto ogni volta che viene chiamato Execute.