PDA

View Full Version : How to Implement Hibernate OpenSessionInView with WCF Services?


crabo
03-31-2008, 04:43 AM
Hi,

As I'm using nhibernate LazyInitial feature, I need to Load a entity,then Init it.
So, how can i keep all of these mess operation in the same SESSION? as OpenSessionInView pattern ?

Also, dealing with Entity Recursive Reference when WCF serialization is a BIG headache.

Any suggestion is appriciate.

crabo
04-02-2008, 03:02 PM
I achieved OSIV by adding a EndPointBehavior as below:


class WcfCallInterceptorBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
//register WcfOpenSessionInView
foreach (DispatchOperation op in endpointDispatcher.DispatchRuntime.Operations)
op.CallContextInitializers.Add(new WcfOpenSessionInView());
}
public void Validate(ServiceEndpoint endpoint) { }
}


I'm still working on serializing Lazy-Init entities for AJAX client over WCF.
A week passed,and I'm almost there now!

Cheers!

crabo
04-03-2008, 03:54 AM
Finally, I got my answer!

1. Replace all DataContractSerializerOperationBehavior.DataContra ctSurrogate to WcfHibernateDataContractSurrogate.

2.Create a WcfHibernateDataContractSurrogate as <b>Tim Vasil</b> described here:
WCF serialization with NHibernate object graphs
timvasil.com/blog14/post/2008/02/WCF-serialization-with-NHibernate.aspx

3.Also add a KnownTypesProvider to all of your Exported Service Contracts.

steinard
04-07-2008, 12:19 AM
Hi!

Good work!

3.Also add a KnownTypesProvider to all of your Exported Service Contracts.If you are not doing SOA, if you know who will consume your services and if you want to reuse your domain assemblies on the other side of the network, then you can use the NetDataContractSerializer (http://www.lhotka.net/weblog/WCFNetDataContractSerializerAndSecurityException.a spx) instead and avoid having to declare all your types.

Cheers,
Steinar.

crabo
04-07-2008, 02:26 AM
Yah, "KnowTypeProvider" is just a assmbly type exporter. It check all the "Contract Types",and return as a type array to the Caller. Note this: I use AJAX as WCF client.

crabo
07-02-2008, 04:25 AM
Finally, I changed my SessionScopeHandler into "IDispatchMessageInspector" Extension.

Because Operation.AfterInvoke always happened before WCF Serializing.

Now it looks like:

public class MessageInspector:IDispatchMessageInspector
{
private Spring.Data.NHibernate.Support.SessionScope Osiv;
public MessageInspector(Spring.Data.NHibernate.Support.Se ssionScope osiv)
{
Osiv = osiv;
}

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (Osiv != null && !Osiv.IsOpen) Osiv.Open();
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
if (Osiv != null) Osiv.Close();
}
}


Tell me what you thinks.

steinard
07-03-2008, 01:12 AM
Hi!

This looks really good and useful. I need to start considering switching to WCF soon I guess...

Cheers,
Steinar.

coreycoto
07-08-2008, 02:39 PM
Crabo,

Have you had any issues with Sessions being closed to soon by using the IDispatchMessageInspector extension? Is the thread that closes the session always going to be the one that opened it?

Thanks,
Corey

crabo
07-11-2008, 02:17 AM
Sorry for my dev enviroment, but, I havn't encounter any error yet.

But I doubt it would be the right way.

May be you should try it and tell me how it's going.

crabo
08-08-2008, 03:41 AM
Some more details here:

In Service.xml :


<object id="WcfOsiv" lazy-init="true" type="Spring.Data.NHibernate.Support.SessionScope,Spring .Data.NHibernate12" />

<object id="WcfNhLazy" lazy-init="true" type="Framework.Integration.WCF.NHibernate.HibernateData ContractSurrogate, Framework.Integration" />

<object id="WcfMsgLog" lazy-init="true" type="Framework.Integration.WCF.DispatchMessageInspector , Framework.Integration">
<constructor-arg name="osiv" ref="WcfOsiv"/>
</object>


So I inject OSIV in my every in/out message. and also replace default to HibernateDataContractSurrogate.

Framework.Integration.WCF.DispatchMessageInspector .cs

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (Osiv != null && !Osiv.IsOpen) Osiv.Open();
}

public void BeforeSendReply(ref Message reply, object correlationState)
{
if (Osiv != null) Osiv.Close();
}



Framework.Integration.WCF.InterceptBehavior.cs

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
if (this.Enabled)
{
#region ICallContextInitializer
//IDictionary ctxs = ctx.GetObjectsOfType(typeof(ICallContextInitialize r));
//foreach (DictionaryEntry de in ctxs)
//{
// //For all operations!
// foreach (DispatchOperation op in endpointDispatcher.DispatchRuntime.Operations)
// op.CallContextInitializers.Add((ICallContextInitia lizer)de.Value);


//}
#endregion

#region IDataContractSurrogate
IDictionary surs = ctx.GetObjectsOfType(typeof(IDataContractSurrogate ));
foreach (DictionaryEntry de in surs)
{
//Register HibernateDataContractSurrogate for Lazy-Properties serialization
foreach (OperationDescription od in endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dcsob =
od.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsob != null)
dcsob.DataContractSurrogate = (IDataContractSurrogate)de.Value;
}

}
#endregion

#region IDispatchMessageInspector
IDictionary msgs = ctx.GetObjectsOfType(typeof(IDispatchMessageInspec tor));
foreach (DictionaryEntry de in msgs)
{
endpointDispatcher.DispatchRuntime.MessageInspecto rs.Add((IDispatchMessageInspector)de.Value);

}
#endregion
}
}