none
Dynamically setting TransactionFlow on WCF operations RRS feed

  • Question

  • I found a similar old topic here.  I'm using WCF with a ChannelFactory and a custom ServiceHost to set some default behaviors for my services.  If I try to programmatically set TransactionFlow on all client and server operations, the transaction doesn't flow correctly.  Effectively I want to change the WCF default from not flowing transactions to flowing transactions.  I don't want to decorate all of my ServiceContract operations with [TransactionFlow], but doing this in code is resulting in the following error on the server:

    Unhandled Exception (Service Transocean.Application.Services.Assignments.AssignmentService) 
    System.ServiceModel.MustUnderstandSoapException: System error.
       at System.ServiceModel.Dispatcher.DispatchOperationRuntime.ValidateMustUnderstand(MessageRpc& rpc)
       at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
       at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
       at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
       at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

    This looks like a bug in WCF and I'm pretty sure it's on the ServiceHost given where the exception happens.  My guess is that there's some WCF code that checks the ServiceContract operations via reflection to see if they're decorated with the TransactionFlowAttribute, but it should be driven by the OperationBehaviors since those can be modified by the ServiceHost.

    Code included below...

    Client Code called on EndPoint on the ChannelFactory:

    private static void AttachTransactionFlowBehavior(ServiceEndpoint endpoint)
    {
        foreach (var op in endpoint.Contract.Operations)
        {
            var opBehavior = op.Behaviors.Find<OperationBehaviorAttribute>();
            if (opBehavior == null)
            {
                opBehavior = new OperationBehaviorAttribute();
                op.Behaviors.Add(opBehavior);
            }
    
            //Ensure Transaction Scope is provided
            opBehavior.TransactionScopeRequired = true;
            opBehavior.TransactionAutoComplete = true;
    
            //Flow transactions for all non-streaming bindings
            var flowBehavior = op.Behaviors.Find<TransactionFlowAttribute>();
            if (flowBehavior != null)
                op.Behaviors.Remove(flowBehavior);
    
            flowBehavior = new TransactionFlowAttribute(TransactionFlowOption.Allowed);
            op.Behaviors.Add(flowBehavior);
        }
    }

    And in ApplyConfiguration of my custom ServiceHost

    foreach (var serviceContract in this.Description.ServiceType.GetInterfaces().Where(t => t.GetCustomAttributes(typeof(ServiceContractAttribute), true).Any()))
    {
        var contractDescription = ContractDescription.GetContract(serviceContract);
    
        foreach (var operationDescription in contractDescription.Operations)
        {
            var opBehavior = operationDescription.Behaviors.Find<OperationBehaviorAttribute>();
            if (opBehavior == null)
            {
                opBehavior = new OperationBehaviorAttribute();
                operationDescription.Behaviors.Add(opBehavior);
            }
    
            //Ensure Transaction Scope is provided
            opBehavior.TransactionScopeRequired = true;
            opBehavior.TransactionAutoComplete = true;
            
            var flowBehavior = operationDescription.Behaviors.Find<TransactionFlowAttribute>();
            if (flowBehavior != null)
                operationDescription.Behaviors.Remove(flowBehavior);
            flowBehavior = new TransactionFlowAttribute(TransactionFlowOption.Allowed);
            operationDescription.Behaviors.Add(flowBehavior);
    		//...
        }
    }

    Wednesday, September 25, 2013 8:50 PM

Answers

  • Hi,

    I found the following in this article, hope it can help you:

    "WCF would add the appropriate TransactionFlow attribute dynamically at run time. This would cause the dynamic proxy to create the transaction headers, and send them to the service. At this point, the service would yield an exception saying that the ServiceContract specified that TransactionFlow is not allowed, while the same binding options used inside a Windows Forms application works, simply because the ServiceContract is shared. To solve this challenge, the binding should specify not to flow transactions."

    Here is an article about TransactionFlow, please try to refer to:
    #TransactionFlow:
    http://msdn.microsoft.com/en-us/magazine/cc163432.aspx .

    Best Regards,
    Amy Peng


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Friday, September 27, 2013 8:41 AM
    Moderator