Reputation: 45
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.
Upvotes: 4
Views: 5537
Reputation: 2984
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.
Upvotes: 1
Reputation: 5801
You need to enable transactions in both the client and service binding by setting WSHttpBindingBase.TransactionFlow=true.
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.
Upvotes: 2
Reputation: 65471
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>
Upvotes: 2