Using NHibernate Session Per Request with WCF Windsor Integration
Okay, this is a quickie, but here is how you can do it, you need to register a UnitOfWorkEndPointBehavior implementation on the container, and make sure that your WCF services are used through the WindsorServiceHost. That is all. What is the UnitOfWorkEndPointBehavior, you ask, here it is:
public class UnitOfworkEndPointBehavior : IEndpointBehavior { public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations) { operation.CallContextInitializers.Add(new UnitOfWorkCallContextInitializer()); } } } public class UnitOfWorkCallContextInitializer : ICallContextInitializer { public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message) { ISession session = factory.OpenSession(); OperationContext.Items["NHibernate_Session"] = session; return session; } public void AfterInvoke(object correlationState) { ((IDisposable)correlationState).Dispose(); } } public static class UnitOfWork { public static ISession Current { get { return (ISession )OperationContext.Items["NHibernate_Session"]; } }
Comments
Awesome stuff! Thanks Ayende - I have been wanting to do something like this for months.
Hi,
Could you please create a simple example with physical layer separation?? Thanks!
Physical layer separation? You mean two different processes?
No, I mean running the IIS and the SqlServer in different machines. So WCF has sense.
Thanks again!
I still don't get the problem, you just need to change the connection string, no?
Yes, but what if I want to separate the business logic from the UI.?
or what is this example for?
Let us take it two steps back.
This is a post about infrastructure. If you want to use NHibernate from your WCF service (or call to a controller that uses NH), this shows you how this can be done easily. I am not following the BL vs. UI discussion, I am afraid.
Thanks Ayende. This doesn't seem to work if the operation is returning an object with a lazy collection. The session is disposed before WCF serializes it and you get a "Failed to lazily initialize a collection - no session" error. Any ideas?
Load it eagerly?
I am sure that the scope of the opened session can be expanded, but I am not to where it should
Thanks. Just for the record I was able to overcome this by creating an IExtension<OperationContext> and disposing the session after the OperationCompleted event.
Excuse me for what probably should be obvious, but I don't see an Items collection off of the System.ServiceModel.OperationContext object. What am I missing?
http://msdn2.microsoft.com/en-us/library/system.servicemodel.operationcontext_members.aspx
I just checked, it doesn't exists, very strange. I assumed that something of this nature would exists
I'm glad I'm not nuts. Do you have any suggestions on how to store the session for the given OperationContext? Everything about this concept makes sense and works for me, I just don't have a good idea for where to store the session.
Thanks,
Jeff
not of the top of my head , I don't know WCF enough to tell.
I'm working on a current design (following this model) for storing Sessions in WCF. Try storing the session in Extensions property of the OperationContext. This would be a class that extended IExtensible<OperationContext>. You can then retrieve this specific extension instance by using OperationContext.Current.Extensions.Find<ExtensionType>(). I'm still working on the design but let me know what you find
Comment preview