How can I implement WCF transaction support in a custom class using CoreService?

I wrote a class to help add and remove recipients to the target publication using the main service. Directions are usually displayed as a string (with XML content) through the Core Service, so I wrote my own wrappers around this, etc.

Now I have a situation where I need to update 2 publishing goals and thought it would be great to use the transaction scope to ensure that both goals are updated at the same time.

However, I am struggling with this.

Working with code (using the standard CoreService WCF client):

TransactionOptions txOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; using(TransactionScope scope = new TransactionScope( TransactionScopeOption.Required, txOptions)) { PublicationTargetData publicationTarget1 = (PublicationTargetData)client.Read("tcm:0-1-65537", readOptions); PublicationTargetData publicationTarget2 = (PublicationTargetData)client.Read("tcm:0-2-65537", readOptions); publicationTarget1.TargetLanguage = "JSP"; publicationTarget2.TargetLanguage = "JSP"; client.Save(publicationTarget1, readOptions); client.Save(publicationTarget2, readOptions); // Stop saving scope.Dispose(); } 

Running this code will successfully roll back the changes that I made (if I broke down to scope.Dispose() and checked the publication targets in Tridion, it successfully changed the target and then β€œundone” the change).

If I now try to use my "advanced publishing class" in a transaction, I cannot destroy it.

 TransactionOptions options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }; using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options)) { ExtendedPublicationTarget target1 = new ExtendedPublicationTarget("tcm:0-1-65537"); ExtendedPublicationTarget target2 = new ExtendedPublicationTarget("tcm:0-2-65537"); target1.Destinations.Add(target1.Destinations[0]); target2.Destinations.Add(target2.Destinations[0]); target1.Save(); target2.Save(); scope.Dispose(); } 

So basically this is the question: what should I do to add a transaction to my .Save () method?

I tried to do this:

 [OperationContract] [TransactionFlow(TransactionFlowOption.Allowed)] public void Save() { _client.Save(targetData, readOptions); } 

But that didn't matter. Is there a way to determine if I currently have a transaction and somehow β€œuse” this transaction? I do not want to require a transaction, I just want to be able to work in one.

Thank you, and sorry for the very long post ... I wanted to make sure that I provided as much information as possible.

+8
wcf transactionscope tridion
source share
1 answer

Best Resource For This: WCF Transaction Propagation

You are missing at least one step. You also need to enable transactions in the binding:

 <bindings> <netTcpBinding> <binding name = "TransactionalTCP" transactionFlow = "true" /> </netTcpBinding> </bindings> 

Is there a way to determine if I am currently in a transaction and somehow β€œuse” this transaction?

Yes. To determine if you are in a transaction, you can check Transaction.Current. If you are in a transaction, you will use it unless you explicitly refuse. This is a beautiful / terrible thing about surrounding transactions.

Figure 5 in WCF Transaction Propagation :

 class MyService : IMyContract { [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod(...) { Transaction transaction = Transaction.Current; Debug.Assert(transaction.TransactionInformation. DistributedIdentifier != Guid.Empty); } } 

If Transaction.Current.TransactionInformation.DistributedIdentifier is empty, the transaction is local and not "current". Note that in the TransactionFlowOptions.Allowed configuration, if the transaction fails, it fails. So this is really the only way to check ... and does not flow, it is easier than you expected.

When I used tranactions for the production service, I actually avoided TransactionFlowOptions.Allowed , because the caller was never sure whether the transaction was actually proceeding. If a configuration configuration error occurs in the deployment, everything will work fine, but the rollbacks will fail ... a very severe error to detect. Therefore, I switched to the required one. The caller can then ensure that the transaction they provided is actually successful. (If the transaction does not flow in the TransactionFlowOptions.Required configuration, you will get an exception.)

+3
source share

All Articles