2009-10-23 9 views
5

nel nostro progetto corrente, stiamo utilizzando ADO.NET Entity Framework come livello dati per l'applicazione. Ci sono alcune attività che richiedono di essere eseguite in una transazione perché c'è molto lavoro da fare nel database. Sto usando un TransactionScope per circondare quelle attività.Problema MSDTC con transazioni in ADO.NET Entity Framework

using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew)) 
{ 
    // Do something... 
    transactionScope.Complete(); 
} 

Il problema è, non appena io sto usando un TransactionScope si verifica un'eccezione:

System.Data.EntityException: Il provider sottostante fallito su Apri. ---> System.Transactions.TransactionManagerCommunicationException: la comunicazione con il gestore delle transazioni sottostante non è riuscita. ---> System.Runtime.InteropServices.COMException (0x80004005): errore HRESULT E_FAIL è stato restituito da una chiamata a un componente COM.

Sembra che questo errore debba fare qualcosa con il MSDTC (Microsoft Distributed Transaction Coordinator). Quando cambio la configurazione di sicurezza di MSDTC viene lanciata un'altra eccezione:

System.Data.EntityException: il provider sottostante non è riuscito in Open. ---> System.Transactions.TransactionManagerCommunicationException: l'accesso di rete per Distributed Transaction Manager (MSDTC) è stato disabilitato. Abilitare DTC per l'accesso alla rete nella configurazione di sicurezza per MSDTC utilizzando lo strumento di amministrazione dei servizi componenti.

Tuttavia, se MSDTC è configurato, lo TransactionScope causerà un errore. Qualcuno sa cosa sta andando storto qui?

risposta

-2

Hmm, sembra funzionare quando cambio la TransactionScopeOption a "Sopprimere la":

using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Suppress)) 
{ 
    ... 
} 

Fa sapere a tutti perché?

+4

Penso in questo caso non utilizza la transazione, ma non ne sono sicuro. –

+0

Sì, questa opzione indica che non dovrebbe prendere parte alla transazione. –

+1

Ricevo lo stesso errore, ma non c'è modo che questa sia la risposta migliore. –

7

Per impostazione predefinita, MSDTC ha disabilitato l'accesso alla rete. Per farlo funzionare si dovrebbe andare a

Pannello di controllo-> Administrative Strumenti-> Componente Servizi-> Component Serivces-> Computes-> Risorse del computer-> destro click-> Proprietà-> MSDTC-> Sicurezza Configurazione

e controllare seguenti caselle Accesso di rete DTC, Consenti in ingresso, Consenti in uscita. L'autenticazione dovrebbe essere scelta in base al proprio ambiente. Si potrebbe anche voler dare uno sguardo allo strumento DTCPing per eseguire il debug delle transazioni distribuite. Per darvi una scorciatoia - potrebbe essere necessario modificare voi Registro di sistema:

HKLM \ Software \ Policies \ Microsoft \ Windows NT \ RPCRestrictRemoteClients = 0 HKLM \ Software \ Policies \ Microsoft \ Windows NT \ RPCEnableAuthEpResolution = 1

per ottenere tutto in funzione.

+0

Grazie, strumento DTCPing mi hanno detto che ci sono alcuni errori endpoint RPC. Ora sto verificando http://support.microsoft.com/kb/306843 e http://support.microsoft.com/kb/839880/EN-US/ forse questa è la soluzione. – Alexander

+0

Per Windows 8, la "Configurazione di sicurezza" può essere trovata qui: http://stackoverflow.com/questions/7694/how-do-i-enable-msdtc-on-sql-server/27263904#27263904 –

0

Ciò significa che è sopprimendo qualsiasi transazione che potrebbe essere in vigore al momento dell'inserimento del blocco di codice, quindi eventuali aggiornamenti apportati al codice non eseguiranno il rollback se la transazione "ambiente" esterna decide di eseguire il rollback.

0

Questo è l'articolo che abbiamo usato per risolvere la nostra, problema simile:

Troubleshooting Problems with MSDTC

Questo è fondamentalmente un addendum al Nikolay R's risposta. Ha già coperto alcuni dei suggerimenti elencati nell'articolo.

Nota: l'articolo fa parte della documentazione di Biztalk, ma può essere applicato a qualsiasi elemento che utilizza MSDTC.

+0

Aggiornamento articolo simile http://msdn.microsoft.com/en-us/library/aa561924.aspx – JeremyWeir

3

Sì, funziona con Supress, perché stai dicendo di sopprimere o ignorare la transazione ambientale e creare una nuova transazione locale. Poiché la transazione è locale, non è una transazione distribuita, quindi non utilizza MSDTC, ma probabilmente non dovresti usare Suppress e dovresti invece usare Required.

0

"Se si utilizza Entity Framework con Transactions, Entity Framework apre e chiude automaticamente una connessione con ogni chiamata al database, quindi quando si utilizzano le transazioni, si sta tentando di estendere una transazione su più connessioni. Questo si eleva a MSDTC."

È possibile passare nel contesto del database alla classe o alla funzione di chiamata nella transazione.

Forse questa è la tua risposta: MSSQL Error 'The underlying provider failed on Open'

0

Soppressione l'operazione è utile se si desidera eseguire un codice che potrebbe non riuscire, ma non si vuole interrompere la transazione a causa di che non riescono.

La domanda che devi porsi è la seguente: Stai accedendo a più di 1 risorsa duratura nel tuo transactionScope? Voglio dire, apri connessioni a più di 1 DB?

Questa è una domanda importante poiché la transazione verrà inoltrata a DTC se si accede a più di una risorsa duratura.

Almeno due risorse durevoli che supportano le notifiche monofase vengono inserite nella transazione. Ad esempio, l'inserimento di una singola connessione con non provoca la promozione di una transazione. Tuttavia, ogni volta che si apre una seconda connessione a un database che provoca l'integrazione del database, l'infrastruttura System.Transactions rileva che si tratta della seconda risorsa duratura nella transazione e la inoltra a una transazione MSDTC. Fonte: MSDN

Se questo è il caso, è possibile risolvere il problema con l'annidamento tuoi transactionscopes correttamente, ad esempio:

//Create rootScope 
using(TransactionScope rootScope = new TransactionScope()) 
{ 
    using(TransactionScope scope2 = new 
    TransactionScope(TransactionScopeOption.Required)) 
    { 
     //Do work on DB1 
     ... 

     //Complete this ambient transaction 
     scope2.Complete(); 
    } 

    using(TransactionScope scope3 = new 
    TransactionScope(TransactionScopeOption.Required)) 
    { 
     //Do work on DB2 
     ... 

     //Complete this ambient transaction 
     scope3.Complete(); 
    } 

    //Complete rootScope 
    //The whole transaction will only be committed if you call 
    //Complete on the rootScope 
    rootScope.Complete(); 

}

È possibile trovare maggiori informazioni su TransactionScopes, come funziona la nidificazione , ... su MSDN.

Spero che questa risposta possa aiutare le persone in futuro.

0

Se il servizio Distributed Transaction Coordinator non è avviato, Entity framework non può connettersi al database. aperte e avviare il Coordinatore Distributed Transaction

Servizi -> Distributed Transaction Coordinator