NServiceBus MSDTC woes
Asked Answered
P

4

8

I am writing this post here in hopes that someone can help me out.

I am trying to implement NServiceBus on an ASP.NET MVC application. I have gone through each and every step to ensure that everything is wired up right. I have an event that passes a Job Id to my handler which then performs a Linq-to-Sql query and looks up a job and then emails an alert. The process is very simple.

However, I cannot for the life of me get MSDTC to work. I keep on getting the following error:

Here is how I have my Bus configured:

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

I am not using Transactions so I know for a fact that MSDTC should not even be called.

My Handler code is as follows:

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();
            }

The endpoint is configured as follows:

public class MessageEndpoint : IConfigureThisEndpoint, AsA_Server, IWantToRunAtStartup

Everything works great. The message arrives correctly when I do:

Bus.Send(message);

However, the MSDTC error occurs as shown:

    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)

I have tried DTC ping and it successfully works so I know for a fact that MSDTC isn't the issue. I have read that NHibernate had similar issues with NServiceBus but I haven't been able to draw any parallels on the same with LINQ to SQL.

Any help on this matter would be very appreciated.

Preciado answered 20/1, 2011 at 9:4 Comment(2)
I should add that when I try this with the database on my local box, everything seems to work. Now I am very curious as to why it wouldn't work with the database on the remote box.Preciado
What is the OS of both the Handler machine and the Database machine? Does the Database machine allow inbound transactions? What is the authentication mechanism set up in DTC for both the Handler machine and the DB machine?Lainelainey
S
10

I had a similar issue and found that the cause was more LINQ-to-SQL than NServiceBus. If you look at your stack trace you'll see the root cause is your LINQ and SqlClient libraries, not NSB. The solution that I ended up using, which may or may not work for you depending on how important it is for your data access to be transactional, was to explicitly turn off transactions in my LINQ to SQL code. In my case, I was simply calling a stored procedure using LINQ to SQL, with code like this:

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

The important part here is the TransactionScope and TransactionScopeOption.Suppress. This ensures LINQ to SQL doesn't try to enlist the call into a transaction using the DTC. This is working in my solution in my message handler (NServiceBus Generic Host).

Sheepdip answered 23/1, 2011 at 14:49 Comment(1)
Very interesting observation. We don't use TransactionScope for our Data Access scenarios. We use the Linq Transactions as and when needed. Of course, we don't really need any transactions for the items we're using on NSB, but I am curious to know how we could utilize them if a situation ever arises? Thank You again for your solution, I nearly pulled my hair out trying to configure MSDTC when the real issue lied within LINQ. Obviously, I didn't think of TransactionScope because wasn't using it.Preciado
T
12

The accepted solution is really a workaround for the problem. I'll suggest you to use DTCPing tool to set up MSDTC properly and find the underlying problems.

Check out this posts for more information:

MSDTC is quite obscure, good luck!

Tacklind answered 6/6, 2011 at 16:29 Comment(0)
S
10

I had a similar issue and found that the cause was more LINQ-to-SQL than NServiceBus. If you look at your stack trace you'll see the root cause is your LINQ and SqlClient libraries, not NSB. The solution that I ended up using, which may or may not work for you depending on how important it is for your data access to be transactional, was to explicitly turn off transactions in my LINQ to SQL code. In my case, I was simply calling a stored procedure using LINQ to SQL, with code like this:

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

The important part here is the TransactionScope and TransactionScopeOption.Suppress. This ensures LINQ to SQL doesn't try to enlist the call into a transaction using the DTC. This is working in my solution in my message handler (NServiceBus Generic Host).

Sheepdip answered 23/1, 2011 at 14:49 Comment(1)
Very interesting observation. We don't use TransactionScope for our Data Access scenarios. We use the Linq Transactions as and when needed. Of course, we don't really need any transactions for the items we're using on NSB, but I am curious to know how we could utilize them if a situation ever arises? Thank You again for your solution, I nearly pulled my hair out trying to configure MSDTC when the real issue lied within LINQ. Obviously, I didn't think of TransactionScope because wasn't using it.Preciado
V
6

What I notice is that you're configuring NServiceBus as a server, which means that it is transactional. I think what you have here is a non-transactional web app which is sending messages to a transactional server.

Vitamin answered 23/1, 2011 at 8:5 Comment(1)
If you mark the endpoint AsA_Server it is equivalent to IsTransactional(true). It actually overrides any IsTransactional(false) that you have set up. Perhaps @AnupMarwadi, you should mark your endpoint as 'AsA_Client'?Popover
I
1

I can remember having issues myself with MSDTC, but for the life of me can't find the blogs/posts/whatever I referenced to solve the issue. Anyway, if that ping program is working it is a bit weird. One suggestion I may add is trying to add the line,

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

just before the .CreateBus() line. If you are using subscriptions this will tell the subscription to stop using transactions, which may be your problem. However be warned doing this will therefore make your subscriptions less reliable, so don't use it in critical situations.

Inhaler answered 21/1, 2011 at 0:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.