4

I have a WPF application and In button click event I am calling WCF service for handling transaction in it. After one transaction complete I am throwing exception. To see whether transaction will rollback or not. But even I got error still transaction got completed it is not aborted in database.

UI Button event:

private void button1_Click(object sender, RoutedEventArgs e)
{
    binding = new WSHttpBinding();
    endpoint = new EndpointAddress("http://localhost:6144/EmployeeService.svc/EmployeeService");

    ChannelFactory<IEmployeeService> cf = new ChannelFactory<IEmployeeService>(binding, endpoint);
    IEmployeeService obj = cf.CreateChannel();

    using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        try
        {
            obj.UpdateProductData(201, 10);
            throw new Exception("Wrong");
            obj.UpdateProductData(202, 15);
            ts.Complete();
        }
        catch (Exception ex)
        {
            ts.Dispose();                          
        }
    }
}

In app.config i already given "transactionFlow="true".

WCF Service:

[OperationBehavior(TransactionScopeRequired=true,TransactionAutoComplete=true)]
public bool UpdateProductData(int ProdId, int Amount)
{
    DALClass objDALProd = new DALClass();
    return objDALProd.UpdateProductData(ProdId, Amount);
}

DALClass:

public bool UpdateProductData(int prodID,int Amount)
{
    try
    {
        objComd.Connection = objConn;
        objConn.Open();
        objComd.CommandText = "UpdateEmployeeData";
        objComd.CommandType = CommandType.StoredProcedure;
        objParam = new SqlParameter("@ProductId", prodID);
        objComd.Parameters.Add(objParam);
        objParam = new SqlParameter("@Amount", Amount);
        objComd.Parameters.Add(objParam);

        objComd.ExecuteNonQuery();
        objConn.Close();
    }
    catch(Exception ex)
    {
        throw new FaultException("Database Error");
    }
    return true;
}

Please let me know where my mistake is. Transaction is not rolled back, even when I am raising exception first transaction is not rolled back.

dcaswell
  • 3,137
  • 2
  • 26
  • 25
user1661171
  • 45
  • 1
  • 4

3 Answers3

2

Have you defined the transaction flow on your WCF contract?

[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]

Have you defined the transaction flow on both the client and server config?

<wsHttpBinding>
<binding name="transactionalWsatHttpBinding"
         transactionFlow="true" />
</wsHttpBinding>
Shiraz Bhaiji
  • 64,065
  • 34
  • 143
  • 252
  • Below is the code added for the WCF Contract But no use... please let me know if there is any other way : [OperationBehavior(TransactionScopeRequired=true,TransactionAutoComplete=true)] public bool UpdateProductData(int ProdId, int Amount) { DALClass objDALProd = new DALClass(); return objDALProd.UpdateProductData(ProdId, Amount); } – user1661171 Sep 18 '12 at 15:16
  • It looks like you put the attribute on the class not the interface – Shiraz Bhaiji Sep 18 '12 at 18:50
2
  1. You need to enable transactions in both the client and service binding by setting WSHttpBindingBase.TransactionFlow=true.

  2. You can check on the service being called if the transaction really is flowing by checking if Transaction.Current.TransactionInformation.DistributedIdentifier is non-zero. If its zero, then the flow is not working and rollback won't happed.

See the answer to How can I implement WCF Transaction support on custom class using CoreService? for more details and links.

Community
  • 1
  • 1
ErnieL
  • 5,773
  • 1
  • 23
  • 27
1

Your client side code looks fine to me, but on the server side, there are a total of 3 attributes you need to get this to work.

Service Interface needs [TransactionFlow] on the operation.

[ServiceContract]
public interface IService
{
  [OperationContract]
  [TransactionFlow(TransactionFlowOption.Allowed)]
  bool UpdateProductData(int ProdId, int Amount);
}

Service Class needs [ServiceBehavior] on the class and [OperationBehavior] on the method:

[ServiceBehavior(TransactionIsolationLevel = IsolationLevel.ReadUncommitted)]
public class Service : IService
{
  [OperationBehavior(TransactionScopeRequired=true,TransactionAutoComplete=true)]
  public bool UpdateProductData(int ProdId, int Amount)
  {
    DALClass objDALProd = new DALClass();
    return objDALProd.UpdateProductData(ProdId, Amount);
  }
}

Also note that these attributes are only one way to do achieve this - you can also do all of this in the config file if desired. Config files make it easier to apply these settings to multiple services in one shot.

Dan Ling
  • 2,965
  • 2
  • 29
  • 43