Apeiron
Apeiron

Reputation: 602

Rolling back transaction scope C#

To further professionalize our testing methods I'm working on some integration testing, using the unit test framework in Visual Studio.

The object under test is a WCF service, my little app runs the service in memory using ServiceHost and I'm able to call the methods exposed in my tests.

This all works fine, but I would like to be able to restore the database after the test using Transactions. To enable this I added the TransactionScopeRequired attribute to the method under test, and tried calling it in a TransactionScope.

But then I noticed TransactionScope does not have a built-in rollback method, so after the method finished the created object was, of course, still in the database.

So I tried not using the 'Complete' method and after some googling I found out just using Dispose manually shoud rollback the transaction. Alas, neither worked. So I went on to start the SQL Server Analyzer to have a look at the generated SQL, perhaps I could find some TRANSACTION statements in there.

The first thing I noticed were that all related queries were executed as stored procedures (generated by EF). The second thing was I couldn't distinguish any sort of transaction management in the related queries.

Now my question: For better or for worse, could this be solved on this level? If so how? Is it possible to work with an 'external' transaction like this?

Upvotes: 0

Views: 1056

Answers (2)

Mimas
Mimas

Reputation: 523

So as I understand your question: 1) you try to open new transaction in Test method using transaction scope 2) you call WCF service inside this Transaction scope 3) your service does some DB changes.

To rollback the changes you simply should not call Complete method of transaction scope. I is always good to create Transaction scope in using, to have automatically Dispose in the end.

So now your service should support transaction propagation from the client. See the same question (Calling WCF service method from transaction scope) and read MSDN articles (https://msdn.microsoft.com/en-us/library/ms730250.aspx)

Note: there are several articles - How to enable transactions , How to configure service

But honestly for me making all that only to make test transactional is overkill, if there are no real requirements from real client to support transactions and no some WCF specific customization on Transport/message/serializer level, like WCF interceptors. I would either tested service class directly, without running service host, or created some kind of TearDown cleanup with manual restoring DB state after the test.

Upvotes: 0

Emmanuel DURIN
Emmanuel DURIN

Reputation: 4913

To rollback the transaction you can either :

  1. Call Transaction.Current.Rollback();
  2. Not call Transaction.Complete();

Check on the server side, that Transaction.Current is not null. So you 'll know if you ve got a current Transaction

To allow the Tx :

  1. On the interface method :

    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Allowed)]
    public void Method(int value);

  2. On the server method implementation :

    [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
    public void Method(int value) { ... }

  3. On the binding allow transaction flow, both on client and server side :

With code :

var wsHttpBinding = new WsHttpBinding();
wsHttpBinding.TransactionFlow = true;

or with XML :

<endpoint address="wsHttpTx" binding="wsHttpBinding" 
    contract="counters.ICountersService" 
    bindingConfiguration="wsHttpTx"/>
   ...
<wsHttpBinding>
  <binding name="wsHttpTx" transactionFlow="true" />
</wsHttpBinding>

Regards

Upvotes: 1

Related Questions