2011-01-20 18 views
8

Scrivo questo post qui nella speranza che qualcuno possa darmi una mano.NServiceBus MSDTC guai

Sto cercando di implementare NServiceBus su un'applicazione ASP.NET MVC. Ho seguito ogni singolo passo per assicurarmi che tutto sia cablato correttamente. Ho un evento che passa un Id del lavoro al mio gestore che quindi esegue una query da Linq a Sql e cerca un lavoro, quindi invia un messaggio di posta elettronica. il processo è molto semplice.

Tuttavia, non riesco a far funzionare MSDTC per tutta la vita. Continuo a ottenere il seguente errore:

Ecco come ho il mio autobus configurato:

Bus = NServiceBus.Configure.WithWeb() 
      .Log4Net() 
      .DefaultBuilder() 
      .XmlSerializer() 
      .MsmqTransport() 
       .IsTransactional(false) 
       .PurgeOnStartup(false) 
      .UnicastBus() 
       .ImpersonateSender(false) 
      .CreateBus() 
      .Start(); 

non sto usando Operazioni quindi so per certo che MSDTC non dovrebbe nemmeno essere chiamato.

codice mio Handler è il seguente:

public void Handle(ApplyJobMessage message) 
    { 
     if (message != null) 
     { 
      using(var context = new MyContext()) 
      { 
       JobPosting posting = (from c in context.JobPostings 
       where c.JobPostingId == message.JobId 
       select c).SingleOrDefault(); 
      } 

L'endpoint è configurato come segue:

public class MessageEndpoint : IConfigureThisEndpoint, AsA_Server, IWantToRunAtStartup 

Tutto funziona alla grande. Il messaggio arriva correttamente quando lo faccio:

Bus.Send(message); 

Tuttavia, l'errore MSDTC si verifica come mostrato:

2011-01-20 00:55:09,744 [Worker.5] ERROR NServiceBus.Unicast.UnicastBus [(null)] 
<(null)> - JobApplicationHandler Failed handling message. 
System.Runtime.InteropServices.COMException (0x8004D02A): The MSDTC transaction 
manager was unable to push the transaction to the destination transaction manage 
r due to communication problems. Possible causes are: a firewall is present and 
it doesn't have an exception for the MSDTC process, the two machines cannot find 
each other by their NetBIOS names, or the support for network transactions is n 
ot enabled for one of the two transaction managers. (Exception from HRESULT: 0x8 
004D02A) 
    at **System.Transactions.Oletx.ITransactionShim.Export**(UInt32 whereaboutsSize, 
Byte[] whereabouts, Int32& cookieIndex, UInt32& cookieSize, CoTaskMemHandle& coo 
kieBuffer) 
    at System.Transactions.TransactionInterop.GetExportCookie(Transaction transac 
tion, Byte[] whereabouts) 
2011-01-20 00:55:09,749 [Worker.5] WARN NServiceBus.Unicast.Transport.Msmq.Msmq 
Transport [(null)] <(null)> - Failed raising 'transport message received' event 
for message with ID=9cb4b136-e110-4b87-81f6-ee4cd3fcaf46\6151 
System.Reflection.TargetInvocationException: Exception has been thrown by the ta 
rget of an invocation. ---> System.Transactions.TransactionManagerCommunicationE 
xception: Communication with the underlying transaction manager has failed. ---> 
System.Runtime.InteropServices.COMException (0x8004D02A): The MSDTC transaction 
manager was unable to push the transaction to the destination transaction manag 
er due to communication problems. Possible causes are: a firewall is present and 
it doesn't have an exception for the MSDTC process, the two machines cannot fin 
d each other by their NetBIOS names, or the support for network transactions is 
not enabled for one of the two transaction managers. (Exception from HRESULT: 0x 
8004D02A) 
    at System.Transactions.Oletx.ITransactionShim.Export(UInt32 whereaboutsSize, 
Byte[] whereabouts, Int32& cookieIndex, UInt32& cookieSize, CoTaskMemHandle& coo 
kieBuffer) 
    at System.Transactions.TransactionInterop.GetExportCookie(Transaction transac 
tion, Byte[] whereabouts) 
    --- End of inner exception stack trace --- 
    at System.Transactions.TransactionInterop.GetExportCookie(Transaction transac 
tion, Byte[] whereabouts) 
    at System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transacti 
on transaction, Byte[] whereAbouts) 
    at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx) 
    at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx) 
    at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transa 
ction) 
    at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transacti 
on transaction) 
    at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection ownin 
gObject) 
    at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection ow 
ningConnection) 
    at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection ou 
terConnection, DbConnectionFactory connectionFactory) 
    at System.Data.SqlClient.SqlConnection.Open() 
    at System.Data.Linq.SqlClient.SqlConnectionManager.UseConnection(IConnectionU 
ser user) 
    at System.Data.Linq.SqlClient.SqlProvider.get_IsSqlCe() 
    at System.Data.Linq.SqlClient.SqlProvider.InitializeProviderMode() 
    at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider 
.Execute(Expression query) 
    at System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Express 
ion expression) 
    at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source) 

Ho provato DTC ping e funziona con successo quindi so per certo che isn MSDTC' t il problema. Ho letto che NHibernate ha avuto problemi simili con NServiceBus ma non sono stato in grado di tracciare parallelismi sullo stesso con LINQ to SQL.

Qualsiasi aiuto in merito sarebbe molto apprezzato.

+0

Devo aggiungere che quando provo questo con il database sul mio box locale, tutto sembra funzionare. Ora sono molto curioso del motivo per cui non funzionerebbe con il database sulla scatola remota. –

+0

Qual è il sistema operativo della macchina del gestore e della macchina del database? Il computer del database consente le transazioni in entrata? Qual è il meccanismo di autenticazione impostato in DTC sia per la macchina Handler che per la macchina DB? –

risposta

10

Avevo un problema simile e ho scoperto che la causa era più LINQ-to-SQL di NServiceBus. Se guardi la traccia dello stack vedrai che la causa principale sono le tue librerie LINQ e SqlClient, non NSB. La soluzione che ho finito per utilizzare, che potrebbe funzionare o meno per te, a seconda di quanto sia importante che il tuo accesso ai dati sia transazionale, era di disattivare esplicitamente le transazioni nel mio LINQ al codice SQL.Nel mio caso, mi è stato semplicemente chiamando una stored procedure utilizzando LINQ to SQL, con codice come questo:

 public void Save(SomeEvent someEvent) 
     { 
      using (new TransactionScope(TransactionScopeOption.Suppress)) 
      { 
       _loggingDatabaseConnection.DataContext.log_ClickInsert(
someEvent.LogDate, 
someEvent.Id, 
someEvent.OtherStuffGoesHere); 
      } 

La parte importante qui è la TransactionScope e TransactionScopeOption.Suppress. Ciò garantisce che LINQ to SQL non provi ad integrare la chiamata in una transazione utilizzando il DTC. Funziona nella mia soluzione nel mio gestore di messaggi (host generico NServiceBus).

+0

Osservazione molto interessante. Non usiamo TransactionScope per i nostri scenari di accesso ai dati. Usiamo le Transazioni Linq come e quando necessario. Naturalmente, non abbiamo davvero bisogno di transazioni per gli articoli che stiamo usando su NSB, ma sono curioso di sapere come possiamo utilizzarli se si verifica una situazione? Grazie ancora per la tua soluzione, ho quasi tirato fuori i miei capelli cercando di configurare MSDTC quando il vero problema era all'interno di LINQ. Ovviamente, non ho pensato a TransactionScope perché non lo usavo. –

1

Posso ricordare di avere problemi con MSDTC, ma per la vita di me non riesco a trovare i blog/post/qualsiasi cosa a cui ho fatto riferimento per risolvere il problema. Ad ogni modo, se quel programma ping funziona, è un po 'strano. Un suggerimento che posso aggiungere sta cercando di aggiungere la riga,

.RunCustomAction(() => 
    NServiceBus.Configure.Instance.Configurer.ConfigureProperty<MsmqSubscriptionStorage>(
    msg => msg.DontUseExternalTransaction, true)) 

poco prima della linea di .CreateBus(). Se si stanno utilizzando abbonamenti, questo dirà all'abbonamento di smettere di usare le transazioni, il che potrebbe essere il tuo problema. Tuttavia, tieni presente che fare ciò renderà le tue iscrizioni meno affidabili, quindi non usarlo in situazioni critiche.

6

Quello che noto è che si sta configurando NServiceBus come server, il che significa che è transazionale. Penso che quello che hai qui è un'applicazione web non transazionale che sta inviando messaggi a un server transazionale.

+1

Se si contrassegna l'endpoint AsA_Server è equivalente a IsTransactional (true). In realtà sovrascrive qualsiasi IsTransactional (falso) che hai impostato. Forse @AnupMarwadi, dovresti contrassegnare il tuo endpoint come "AsA_Client"? –