PDA

View Full Version : Spring.NET, NHibernate, WCF Services and Lazy Initialization


coreycoto
05-06-2008, 03:19 PM
After some frustraition, I have developed a solution that enables the use NHibernate's Lazy Initialization within WCF Webservices. I was only able to do so by standing on the shoulders of those who came before me (stienard and crabo).


public class ServiceOpenSessionInViewModule : IDisposable
{
private OpenSessionInViewModule osiv;

public ServiceOpenSessionInViewModule(OpenSessionInViewMo dule osiv)
{
this.osiv = osiv;
this.osiv.Open();
}

public void Dispose()
{
osiv.Close();
}
}

public class ServiceOpenSessionInViewInvoker : IOperationInvoker
{
private IOperationInvoker innerOperationInvoker;

public ServiceOpenSessionInViewInvoker(IOperationInvoker innerOperationInvoker)
{
this.innerOperationInvoker = innerOperationInvoker;
}

public object[] AllocateInputs()
{
return this.innerOperationInvoker.AllocateInputs();
}

public object Invoke(object instance, object[] inputs, out object[] outputs)
{
object value;

using (new ServiceOpenSessionInViewModule(new OpenSessionInViewModule()))
{
value = this.innerOperationInvoker.Invoke(instance, inputs, out outputs);
}

return value;
}

public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return innerOperationInvoker.InvokeBegin(instance, inputs, callback, state);
}

public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return innerOperationInvoker.InvokeEnd(instance, out outputs, result);
}

public bool IsSynchronous
{
get { return innerOperationInvoker.IsSynchronous; }
}
}

[AttributeUsage(AttributeTargets.Method)]
public class ServiceOpenSessionInViewBehaviorAttribute : Attribute, IOperationBehavior
{
public void Validate(OperationDescription operationDescription)
{
if (operationDescription.SyncMethod == null)
{
StringBuilder sb = new StringBuilder();
sb.Append("The ServiceOpenSessionInViewBehaviorAttribute only works for Synchronous methods. ");
sb.Append("OperationDescription.SyncMethod returned 'null'.");

throw new InvalidOperationException(sb.ToString());
}
}

public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
if (dispatchOperation.Invoker.IsSynchronous == false)
{
StringBuilder sb = new StringBuilder();
sb.Append("The ServiceOpenSessionInViewBehaviorAttribute only works for Synchronous methods. ");
sb.Append("OperationDescription.SyncMethod returned 'false'.");

throw new InvalidOperationException(sb.ToString());
}

dispatchOperation.Invoker = new ServiceOpenSessionInViewInvoker(dispatchOperation. Invoker);
}

public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}

public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
}


Add the following method attribute to your WCF Service Method:

[ServiceOpenSessionInViewBehavior]
public String GetMessage(int messageId)
{
//Execute NHibernate query

return "Hello World";
}


The implementation has been working pretty successfully for me. Please let me know if you have any questions or suggestions.

Thanks,
Corey

bchebrou
06-13-2008, 12:43 PM
Hello,

I've a question about your code, i tried your code and it worked well during the execution of the service. But I'have always a problem during the serialization of the result. Because with you code the Session is closed before the serialization.

So, if we have a class Order with a collection of OrderLines. If the collection of OrderLines is LazyLoaded and marked as [DataMember], the DataContractSerializer try to serialize the Collection and here we have the LazyLoading Exception.

I know, that I can set the fetch mode of the collection to force the loading before the serialization :

criteria.SetFetchMode("OrderLines", FetchMode.Join);

But do you think it's possible to close the session after the serialization ?

And always with the same sample, do you have any idea, if for a specific service i don't want the OrderLines will be serialized how I can say to NHibernate of not load at all the OrderLines. Because in lazy loading the DataContractSerializer during the serialization will try to access the collection and try to load it, and if for performance reason i don't want to send the order lines over the wire, i don't see how i can avoid that behaviour.

Regards,

Benjamin

coreycoto
07-08-2008, 02:34 PM
Hi Benjamin,

I haven't experianced the serialization issues because we are not serializing Hibernate DTOs. We using the View Helper pattern to transform the DTOs into View Objects used in the presentation tier.

Thanks,
Corey