TransactionIsolationLevel and multiple service contracts

I have a service which implements several contracts, which works fine, e.g.

class MyService : IMyContract1, IMyContract2
{
// Implement both interfaces in here
}

This works fine, but in my case IMyContract2 has an operation where I want to flow a transaction, so I use an attribute to set this on the operation:

[OperationBehavior(TransactionAutoComplete=true, TransactionScopeRequired=true)]

I want to set the isolation level for this, so I add this attribute to the Service:

[ServiceBehavior(TransactionIsolationLevel=IsolationLevel.ReadCommitted)]

The problem is, when I try to host this service, I get the following exception:

Unhandled Exception: System.InvalidOperationException: The service 'MyService' is configured with a TransactionIsolationLevel but no operations are configured with TransactionScopeRequired set to true. TransactionIsolationLevel requires at least one operation with TransactionScopeRequired set to true.

I've played around with this and found that if I switch the order of the interface declarations, then it works, i.e.

[ServiceBehavior(TransactionIsolationLevel=IsolationLevel.ReadCommitted)]
class MyService : IMyContract2, IMyContract1
{
// Implement both interfaces in here
}

I guess this means that it is only checking the first interface for methods which have TransactionScopeRequired set true, which is a bug. I can use this to get around it in this case, but now I'm trying to inherit from a base class which implements the interface which requires that I do not flow transaactions (i.e. has no operations configured with TransactionScopeRequired set to true). As C# insists that the base class appears first in the list, I can't re-order them to fix the problem!

[ServiceBehavior(TransactionIsolationLevel=IsolationLevel.ReadCommitted)]
class MyService : MyServiceBase, IMyContract2, IMyContract1
{
// MyServiceBase implements IMyContract1
// Implement IMyContract2 interface in here
}

Does anyone have a workaround for this? And can anyone at Microsoft help and fix the bug for future releases, or explain this 'feature'?

[2209 byte] By [MatthewWright] at [2007-12-24]
# 1

Matthew,

Can you post the definition of the IMyContract1 and IMyContract2? The settings on those are relevant to the ability to flow transactions, as is the configured binding so you could include detail on that too please.

Thanks,

Andy Milligan

AndyMilligan at 2007-10-8 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 2

Matthew,

Just curious, as a workaround can you use TransactionScope (in code instead of annotating with OperationBehaviour) in your Operation that needs transaction. Something like

public void MyOperation()

{

using (TransactionScope ts = new TransactionScope(TransactioScopeOption.Required, TransactionOptions.IsolationLevel.ReadCommitted) )

{

......

ts.Complete();

}

}

# 3

That's a good point: does it still flow the transaction then? I'll try it and see.

In response to the other question, I'm not sure that the implementation of IMyContract1 and IMyContract2 actually make any difference, but here they are anyway:

[ServiceContract(SessionMode = SessionMode.Required)]
interface IMyContract1
{
[OperationContract(IsInitialising=true)]
int Initialise(string Name);

[OperationContract(IsInitialising=false)]
string FetchNextRole();
}

[ServiceContract]
interface IMyContract2
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
bool Test();
}

The abstract class MyServiceBase is a trivial implementation of IMyContract1, which I'm sure you can knock together yourself.

I don't have a problem getting the transactions to flow: I had that working fine before I tried adding the second contract, and I have it working on many other classes. What I have the problem with is that the following code throws an exception:

Uri baseAddress = new Uri("http://server:9011/MyService");
System.ServiceModel.ServiceHost host =
new System.ServiceModel.ServiceHost(typeof(MyService), baseAddress);
host.AddServiceEndpoint(typeof(IMyContract1), new WSHttpBinding(SecurityMode.Message, false), baseAddress);

host.Open();

The exception message is in my original post.

Regards,

Matthew

MatthewWright at 2007-10-8 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 4

There appears to be an issue with the way the framework verifies contracts with interfaces. I'll forward this bug to the right team internally.

In the meantime, the workaround appears to be that you place the interface with TransactionFlow first in the declaration list.

Jack

JackLoomis-MSFT at 2007-10-8 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...

Visual Studio Orcas

Site Classified