TransactionScope in WCF service or in the client proxy? - wcf

Regarding transactions in WCF services, shall I use TransactionScope object in client side application that consumes the service or in the service code? Please explain why.

It depends on your usage scenario. If your service function executes multiple calls that should be grouped in a transaction you should use a Transaction in your service function
Using a Transaction in your client code is useful when your client calls multiple service functions that should be bundled together in one transaction.
So for example:
public void MyServiceFunction1()
{
using (TransactionScope transaction = new TransactionScope())
{
// execute some logic inside this service function that should be in a transaction
}
}
public void MyServiceFunction2()
{
using (TransactionScope transaction = new TransactionScope())
{
// execute some logic inside this service function that should be in a transaction
}
}
public void MyClientFunction()
{
using (TransactionScope transaction = new TransactionScope())
{
// Bundle both service calls in one transaction
MyService service = new MyService();
service.MyServiceFunction1();
service.MyServiceFunction2();
}
}
Be aware however that you need to configure your WCF bindings correctly to make sure that the transaction is passed from client to server. It will then automatically promote in a distributed transaction.

Making a service transaction aware means that if passed a transaction it will enlist in it
Whoever consumes the service, be it a client application or another service, must create a transaction (or already be running in a transaction flowed to them) for the service to enlist - hence they must call the service from within a TransactionScope (either explicitly or implicitly by having the transaction flowed to them).
If the operation is marked as TransactionFlow(TransactionFlowOption.Allowed) then the consumer does not have to have a transaction, but then the service will not execute in a flowed transation
If the operation is marked as TransactionFlow(TransactionFlowOption.Mandatory) then the client must flow a transaction, and assuming the other bits are aligned (OperationBehavior creates auto enlists, etc) then the operation will run in the same distributed transaction

Related

Use of wcf transaction with example

I read about the wcf transactions but not able to find out its use. Does anybody know any scenario where we should use wcf transaction. Realtime example would be helpful to understand.
A WCF Transaction allow us to make operations that consumers can use inside transactions. We can call a wcf service operation inside a transaction scope (for example) and ensure that our operation will be atomic. It's really helpful to ensure integrity in our operations.
For example, suppose that we have two wcf operations:
debit(double mont,string account);
deposit(double mont,string
If I've implemented wcf transactions I can build up a transfer operation mixing the two operations in a transaction and I'll be sure that there will not be any inconsistency. If any of service calls fail , the entire transaction will rollback.
try
{
using(TransactionScope scope = new TransactionScope())
{
IserviceClient client = new IserviceClient();
client.debit(499,"acdf5-sdsd-4546-223-2");
client.deposit(499,"45651-as4d-ghhd-222-1");
scope.Complete();
}
}
catch
{
Debug.WriteLine("Some error occurred...");
}
It can be helpful. http://www.codeproject.com/Articles/183708/WCF-Transactions-Brief-Introduction
EDIT: You should use transactions when the service operation changes any state (a database insert,update or delete, any file modification) although transactions are not useful when you do a simple read operation for example.

WCF service void method Will operation complete with Windows Impersonation

I have a WCF which is configured on Windows Authentication. This means that only authenticated Windows users will be able to access. I have a method which does not return anything but spins up a thread that does some long running task under the called windows user impersonation.
My code is below:
public void SampleTask();
{
Task.Factory.StartNew(this.Activity);
}
private void Activity()
{
WindowsIdentity identity = ServiceSecurityContext.Current.WindowsIdentity;
using (WindowsImpersonationContext ctx = identity.Impersonate())
{
// Log status in a log database as "In Progress"
// Do long running task (accessing database as current user)
// retreive the results and save in a file
// Update the log database as "Complete"
}
}
My question is will the task still complete of retrieving the results and saving it and put the status as it should. Or will the impersonation will not work as there will be no open session. Or am I mistaken
Regards,
Girija Shankar
The session should remain open as long as the method is executing. Even if the method is returning void, the request that started the execution of the method will be replied to.
If you don't need a reply from the service, you can use the IsOneWay = true attribute on the method, which will tell the service to not send a reply to the client. Since this is a long-running method that is not returning data to the client, that makes it a good candidate for being a one-way method. In this case I'm not sure if the session would remain open or not, but it doesn't matter because the impersonation context will be scoped to the service, and have no dependency on the client.
In your method, you can see this because of the declaration:
WindowsIdentity identity = ServiceSecurityContext.Current.WindowsIdentity;
The variable identity is scoped to the Activity method.
using (WindowsImpersonationContect ctx = identity.Impersonate())
The variable ctx is likewise scoped to the using block within the Activity method.
The only time you would run into a problem that I can think of is if the service throws an exception and crashes - then of course the method wouldn't finish.
To sum up, since the impersonation is based on the identity the service is running under, and you're not returning any data to the client, session should have no impact on both the method running to completion or the identity the service is running under.

WCF and NHibernate transaction scope

I have client calls coming in to WCF Service and then through Fluent NHibernate querying the db.
At the moment WCF is left as it's default (i.e., per call).
And in my code I do something like this:
using (_repository.DbContext.BeginTransaction()) {
try {
_repository.SavePerson(object);
_repository1.SaveAddress(object1);
} catch {
_repository.DbContext.RollbackTransaction();
throw;
}
}
since DbContext is the same for both _repository and _repository1. Do I need to do a RollBack on _repository1?
Also now since the Save methods in the repositories,
the Session object is used to save the objects.
What I need to know is,
is this Session the same for both calls, or are they 2 different ones? I am assuming they to be the same since
I am grouping them in transaction scope as one unit of work.
Also How does this coordinate with WCF calls, do I need to handle transactions from WCF side as well?
Your question can not be answered by someone who does not have access to your code. NHibernate session are not created by WCF, you do have some custom code for creating a session. If you want do stuff to r1 and r2 at the same time and rollback only r1, you need to have to sessions with a transaction on each session. Now you can rollback r1 without touching r2.
The solution is to open a second session from your session factory.

NHibernate + WCF + Windows Service and WcfOperationSessionContext class

I have a Windows Service Application
in which i create WCF services in it.
One of the services is data
services: add, delete,
read , updatte data via
WCF.
WCF use NHibernate for data manipulation
So my guestions are:
Any advice (best practice) for session management for Hibernate using with WCF?
Anybody knows anything about
WcfOperationSessionContext (hibernate 3.0) class?
how to use it with WCF?
Well to make it concrete :
Suppose that i have WCF Service called DataServices
class WCFDataService .....
{
void SaveMyEntity(MyEntity entity)
{
.....................?? // How to do? Best Way
// Should i take one session and use it all times
// Should i take session and dipsose when operation finished then get
//new session for new operations?
// If many clients call my WCF service function at the same time?
// what may go wrong?
// etc....
}
}
And I need a NHibernateServiceProvider class
class NHibernateServiceProvider ....
{
// How to get Session ?? Best way
ISession GetCurrentSession(){.... }
DisposeSession(){ ....}
}
Best Wishes
PS: I have read similiar entries here and other web pages. But can not see "concrete" answers.
The WcfOperationSessionContext, similar to ThreadStaticSessionContext and WebRequestSessionContext is an implementation for a session context. The session context is used to bind (associate) a ISession instance to a particular context.
The session in the current context can be retrieved by calling ISessionFactory.GetCurrentSession().
You can find more information about session context here.
The WcfOperationSessionContext represents a context that spans for the entire duration of a WCF operation. You still need to handle the binding of the session in the begining of the operation and the unbinding/commiting/disposal of the session at the end of the operation.
To get access to the begin/end actions in the wcf pipeline you need to implement a IDispatchMessageInspector. You can see a sample here.
Also regarding WCF integration: if you use ThreadStatic session context it will appear to work on development, but you will hit the wall in production when various components (ex: authorization, authentication ) from the wcf pipeline are executed on different threads.
As for best practices you almost nailed it: Use WcfOperationSessionContext to store the current session and the IDispatchMessageInspector to begin/complete your unit of work.
EDIT - to address the details you added:
If you configured WcfOperationSessionContext and do the binding/unbinding as i explained above, all you have to do to is inject the ISessionFactory into your service and just use factory.GetCurrentSession(). I'll post a sample prj if time permits.
Here is the sample project
The model we use for managing NHibernate sessions with WCF is as follows:
1) We have our own ServiceHost class that inherits from System.ServiceModel.ServiceHost which also implements ICallContextInitializer. We add the service host instance to each of the operations in our service as follows:
protected override void InitializeRuntime()
{
base.InitializeRuntime();
foreach (ChannelDispatcher cd in this.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
foreach (DispatchOperation op in ed.DispatchRuntime.Operations)
{
op.CallContextInitializers.Add(this);
}
}
}
}
public void AfterInvoke(object correlationState)
{
// We don't do anything after the invoke
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
OperationContext.Current.Extensions.Add(new SessionOperationContext());
return null;
}
The BeforeInvoke simply makes sure that the OperationContext for each WCF call has it's own session. We have found problems with IDispatchMessageInspector where the session is not available during response serialisation - a problem if you use lazy loading.
2) Our SessionOperationContext will then be called to attach itself and we use the OperationCompleted event to remove ourselves. This way we can be sure the session will be available for response serialisation.
public class SessionOperationContext : IExtension<OperationContext>
{
public ISession Session { get; private set; }
public static SessionOperationContext Current
{
get
{
OperationContext oc = OperationContext.Current;
if (oc == null) throw new InvalidOperationException("Must be in an operation context.");
return oc.Extensions.Find<SessionOperationContext>();
}
}
public void Attach(OperationContext owner)
{
// Create the session and do anything else you required
this.Session = ... // Whatever instantiation method you use
// Hook into the OperationCompleted event which will be raised
// after the operation has completed and the response serialised.
owner.OperationCompleted += new EventHandler(OperationCompleted);
}
void OperationCompleted(object sender, EventArgs e)
{
// Tell WCF this extension is done
((OperationContext)sender).Extensions.Remove(this);
}
public void Detach(OperationContext owner)
{
// Close our session, do any cleanup, even auto commit
// transactions if required.
this.Session.Dispose();
this.Session = null;
}
}
We've used the above pattern successfully in high-load applications and it seems to work well.
In summary this is similar to what the new WcfOperationSessionContext does (it wasn't around when we figured out the pattern above;-)) but also overcomes issues surrounding lazy loading.
Regarding the additional questions asked: If you use the model outlined above you would simply do the following:
void SaveMyEntity(MyEntity entity)
{
SessionOperationContext.Current.Session.Save(entity);
}
You are guaranteed that the session is always there and that it will be disposed once the WCF operation is completed. You can use transactions if required in the normal way.
Here is a post describing, in detail, all the steps for registering and using the WcfOperationSessionContext. It also includes instructions for using it with the agatha-rrsl project.
Ok, after few days of reading internet posts etc. all approaches shown in the internets seems to be wrong. When we are using UnitOfWork pattern with NH 3^ with nhibernate transaction this all aprochaes are producing exceptions. To test it and proof that we need to create test enviroment with MSMQ transaction queue, special interface with OneWay operation contract with transaction required set on it. This approach should works like this:
1. We put transactionally message in queue.
2. Service is getting transactionally messege from queue.
3. Everything works queue is empty.
In some cases not so obious with internet approaches this does not work properly. So here are expamples which we tested that are wrong and why:
Fabio Maulo approach: Use ICallContextInitializer - open NH session/transaction on BeforeCall, after that WCF is executing service method, on AfterCall in context initializer we call session.Flush + transaction.commit. Automaticly session will be saved when transaction scope will commit operation. In situation when on calling transaction.Complete exception will be thrown WCF service will shutdown! Question can be ok, so take transaction.Complete in try/catch clausule - great! - NO wrong! Then transaction scope will commit transaction and message will be taken from queue but data will not be saved !
Another approach is to use IDispatchMessageInspector - yesterday I thought this is best approach. Here we need to open session/transaction in method AfterReceiveRequest, after WCF invoke service operation on message dispatcher inspector BeforeSendReply is called. In this method we have info about [reply] which in OneWay operation is null, but filled with fault information if it occured on invoking service method. Great I thought - this is this ! but NOT! Problem is that at this point in WCF processing pipe we have no transaction ! So if transaction.Complete throw error or session.Flush will throw it we will have not data saved in database and message will not come back to queue what is wrong.
What is the solution?
IOperationInvoker and only this!
You need to implement this interface as a decorator pattern on default invoker. In method Invoke before call we are openning session/transaction open then we call invoke default invoker and after that call transaction.complete in finally clausule we call session.flush. What types of problem this solves:
1. We have transaction scope on this level so when complete throws exception message will go back to queue and WCF will not shutdown.
2. When invocation will throw exception transaction.complete will not be called what will not change database state
I hope this will clear everyones missinformation.
In some free time I will try to write some example.

Wcf Duplex: Retrieve Client Connection?

Hi
Maybe this look like ridiculous but this is problem at least for me
I wrote duplex WCF service, in my service I need to get active client service and save them, and when with occurred special event I call specific client and send some values for it. So I define dictionary and save client in that. (With this method client calls)
public static Dictionary<int, IServiceCallbak> ActiveClients;
public void IConnect(int SenderId)
{
if (ActiveClients == null)
ActiveClients = new Dictionary<int, IServiceCallbak>();
Client = OperationContext.Current.GetCallbackChannel<IServiceCallbak>();
if (ActiveClients.Count(ac => ac.Key == SenderId) > 0)
ActiveClients.Remove(SenderId);
ActiveClients.Add(SenderId, Client);
}
So then when I need find client from that dictionary and call specific method : Client.DoSomthing().
Also when Client wants to exit, it calls IDisconnect method which will remove client from dictionary.
so I manage Active-client in service!!!
But there is problem in client for managing themselves
After a period time which define in app.config service connection will be closed and you should renew that and then open the service.
So in this case:
1)Is there any solution for recreate and open the service object automatically in client.
2)Or when in server side when service want call clients, check state of client-service-object from that dictionary, and reopen connection from server-side (Ridiculous-solution)
Edit
I think better solution is to handle Suggestion 1, I don't know how!!!.
So for now the question is: Is way exist to do Suggestion 1 Or not? Previously I describe Suggestion 1 in Comment:
"And automatically refer to event for this case(like closing or aborting), but I don't find anything for doing this in Service-Client"
In order to prevent the server side from closing the connection you could set up a Heartbeat() method in the contract that the client could call periodically. This is not ideal however, for one thing because the underlying socket could drop and this does nothing to remedy that.
As far as your suggestion 1) if on the client side you are inheriting from ClientBase you are somewhat stuck in that no indication of a problem may be given until you call a method to route to the service. You would have to wrap the call in a try / catch and then employ some reconnect logic:
public class MyClass : ClientBase<IContract>, IContract
{
public void ServiceMethod(String data) {
try {
base.Channel.ServiceMethod(data);
}
catch (CommunicationException ce) {
// Perform some reconnect logic here
base.Channel.ServiceMethod(data);
}
}
}
Your comment for suggestion 2) is correct, if there are any firewalls between the server side and client they would most likely not allow the connection
Edit:
To expand on my suggestion for 1), you would need to create a new connection when the call to the service fails with a CommunicationException. The simplest approach would be to create the service channel in the constructor and then create another when the call fails:
class ServiceClient {
Service1Client mService; // Class generated by VS tool
public ServiceClient()
: base() {
mService = new Service1Client();
}
#region IService1 Members
public string GetData(int value) {
CommunicationState state = mService.State;
if (state == CommunicationState.Closed || state == CommunicationState.Faulted) {
mService = new Service1Client();
}
try {
// Note: The state checked above may not be accurate,
// hence the try...catch
return mService.GetData(value);
}
catch (CommunicationException) {
mService = new Service1Client(); // Reconnect logic
return mService.GetData(value); // If it fails again we are out of luck...
}
}
#endregion
}
Edit2:
In WCF the session is handled by the client, if the session between the client and the service is lost, I know of no way to restore that session, either from the client or the service. You are, unfortunately, stuck here.
If the service wants to send via the callback with a broken session, simply put, it can't. Because of the way networks work the service may not know the actual client address. This and various other issues (like firewalls) mean that trying to reestablish a connection to the client from the service just isn't practical. The only approach for the service is to store what data it wanted to send to the client and send it when the service detects that the client has reconnected.
There is no guarantee that the client will know of the underlying socket dropping, until the client tries to send something over the socket, hence the try...catch. Recreating the channel from the client once it becomes aware of a broken connection is the only way I know of to handle the issue; which is what the code example does.
The heartbeat idea is a way to proactively deal with broken connection. Its efficiency depends on your requirements as to how fast you need to detect a broken connection and how many clients are present. The more clients connected the longer the heartbeat would have to be so that you don't put a load on the network at the service.
Edit3:
After some additional digging there may be a way to do what you want automatically. You can create what is known as a Reliable Session. Activating this involves creating additional entries in the config:
<netTcpBinding>
<binding>
<reliableSession ordered="Boolean"
inactivityTimeout="TimeSpan"
enabled="Boolean" />
</binding>
</netTcpBinding>
It is also available for Http related bindings, check out the link to the Microsoft documentation on the feature.