Sending NHibernate entities over the WCF wire
Posted by Davy Brion on January 3rd, 2008
Last year, Tim Scott posted this very good article on how to distribute NHiberate entities through WCF services. In it, he mentions this:
We should mention that this application uses NHibernate 1.02. As of this writing, NHibernate has released version 1.2. We tested the application with NHibernate 1.2 before changing to the NetDataContractSerializer, and verified that it exhibits the same problem. We have not verified that the solution described here will work with NHibnerate 1.2, although we expect it will.
I created a small sample that uses his solution with NHibernate 1.2 and my Northwind example and in this post, we’ll walk through the sample. But first, a little bit of background information. By default, WCF services use the DataContractSerializer to serialize/deserialize types. But when you’re using NHibernate, you’re most likely using some of the persistent collection types and proxies. Some people just want to use the same types serverside and clientside. For instance, retrieving a Customer object with his Orders collection through a service, manipulating one of the Order objects clientside, perhaps remove an order from the collection, send the object graph back to the server, attach it to an nhibernate session, persist the whole thing and be done with it. I’m still somewhat undecided as to whether or not this is a good way of doing things but that’s beside the point of this post. Default WCF services do not make this possible but you can make it work rather easily. WCF includes the NetDataContractSerializer which differs from the normal DataContractSerializer in that it includes CLR type information in the serialized data. This makes the above scenario possible. You do lose all interoperability with other platforms, and your clients need the same types you use server side.
First of all, this is the service contract:
[ServiceContract]
public interface ICustomerService
{
[UseNetDataContractSerializer]
[OperationContract]
IList<Customer> GetCustomersWithTheirOrders();
[UseNetDataContractSerializer]
[OperationContract]
void PersistCustomer(Customer customer);
}
The [UseNetDataContractSerializer] is not a standard WCF attribute, but is a part of Tim Scott’s solution. You can find the implementation of the attribute in his post, or in my code which you can download at the bottom of this post. It basically comes down to this: the serialization behavior of operations decorated with this attribute is modified to use the NetDataContractSerializer instead of the default DataContractSerializer.
The implementation of the service contract looks like this:
public class CustomerService : ICustomerService
{
private static readonly ISessionFactory _sessionFactory;
static CustomerService()
{
try
{
Configuration configuration = new Configuration().AddAssembly(“Northwind.Domain”);
_sessionFactory = configuration.BuildSessionFactory();
}
catch (Exception e)
{
Console.Write(e);
throw;
}
}
public IList<Customer> GetCustomersWithTheirOrders()
{
using (ISession session = _sessionFactory.OpenSession())
{
return session.CreateCriteria(typeof(Customer))
.SetFetchMode(“Orders”, FetchMode.Join)
.SetResultTransformer(CriteriaUtil.DistinctRootEntity)
.List<Customer>();
}
}
public void PersistCustomer(Customer customer)
{
using (ISession session = _sessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(customer);
session.Flush();
transaction.Commit();
}
}
}
}
First of all, this is just an example, that’s why the ISessionFactory is created within the service implementation, in a real system i wouldn’t do this. Anyway, the GetCustomersWithTheirOrders method returns a list of all Customers, with their Orders. An Order contains references to an Employee and a Shipper. The Employee and Shipper will not be retrieved from the database, but NHibernate will initialize them with proxy objects to enable lazy-loading. Obviously, the lazy-loading won’t work once you’re outside of the scope of the NHibernate session, but it’s important to note that there will be proxies in our object graph.
At first i had decorated my entity classes with the [DataContract] and [DataMember] attributes but that really messed up the deserialization of the proxies. Now my Entity classes are only decorated with the [Serializable] attribute. NetDataContractSerializer should work in both cases, but i only got it working properly when they were [Serializable].
Right, so now we have the service contract and the implementation, it’s time to host it. My solution contains an example of a console host as well as a service hosted in IIS. For this post, i’ll just go over the console host and console client. You can find the IIS example (which is practically identical anyway) in the downloadable solution.
So, in the console host project, i have the following in my app.config file:
<system.serviceModel>
<services>
<service name=“ServiceImplementation.CustomerService“ behaviorConfiguration=“customerServiceBehavior“>
<endpoint contract=“ServiceInterface.ICustomerService“ binding=“wsHttpBinding“
bindingConfiguration=“customerServiceBinding“ />
<endpoint contract=“IMetadataExchange“ binding=“mexHttpBinding“ address=“mex“ />
<host>
<baseAddresses>
<add baseAddress=“http://localhost:8000/CustomerService“/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name=“customerServiceBinding“ maxReceivedMessageSize=“2147483647“ />
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name=“customerServiceBehavior“ >
<serviceMetadata httpGetEnabled=“true“ httpGetUrl=“”/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
The service is then started like this:
private static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(CustomerService)))
{
host.Open();
Console.WriteLine(“press ENTER to quit”);
Console.ReadLine();
}
}
As you can see, nothing special here… it’s pretty much your typical self-hosting WCF example. Except that the maximum message size has been increased since we’ll be sending large object graphs over the wire.
The client configuration looks like this:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name=“customerServiceBinding“ maxReceivedMessageSize=“2147483647“ />
</wsHttpBinding>
</bindings>
<client>
<endpoint address=“http://localhost:8000/CustomerService“ binding=“wsHttpBinding“ name=“CustomerServiceEndPoint“
bindingConfiguration=“customerServiceBinding“ contract=“ServiceInterface.ICustomerService“ />
</client>
</system.serviceModel>
And the client uses the service like this:
private static void Main(string[] args)
{
ChannelFactory<ICustomerService> factory = new ChannelFactory<ICustomerService>(“CustomerServiceEndPoint”);
ICustomerService proxy = factory.CreateChannel();
IList<Customer> customers = proxy.GetCustomersWithTheirOrders();
}
I didn’t write a test for this to prove it works, but if you step through it and you explore the returned object graph using the debugger, you’ll see that everything is of the correct type… even the proxies make it through correctly. Manipulating the graph and using the PersistCustomer method also works, but it’s not in this example anymore because i didn’t wanna pollute my database every time i ran it to test it.
I did have problems when i was hosting the service both in the console and through IIS at the same time… some requests would then fail to deserialize the returned graph properly. If you don’t run both hosts at the same time, it works. I have no idea why this caused issues, but after wasting a few hours trying to figure it out, i just gave up. You can reproduce it by running the ServiceConsoleHost, ServiceClient and ServiceWebClient projects in the solution. Sometimes that just works as well, so you may have to try a few times to get it to fail. So if anyone can shed some light on that issue, i’d be most interested in hearing about it
You can download the solution here. Note that this is a Visual Studio 2008 solution…
January 7th, 2008 at 4:44 am
Hi thx for the example.
Is it the same serializtion problem with webservice and nhibernate. Will this solution work also with webservices
thx
Luc
January 7th, 2008 at 8:16 am
No this is a WCF-specific solution so this won’t work with classic ASP.NET webservices
January 30th, 2008 at 9:01 pm
Do you have the examples in a Visual Studio 2005 project format????
January 31st, 2008 at 8:37 am
Sorry, i only have Visual Studio 2008 around these days
February 6th, 2008 at 5:52 pm
Is there a way to extend the NHibernate session from the service to the client to enable lazy loading for the client? Passing the proxied object to the client seems undesirable since it would throw an exception if the client tried to access the proxied object/property.
February 7th, 2008 at 7:47 am
I don’t think that’s possible but i’m not sure… I don’t think it would be a good idea though. You’re probably better off fetching all the data you need for your use case and sending it back to the client in one go. Otherwise, you could be looking at crossing the wire for every lazy loaded property you access which would almost certainly cause performance problems. And if you access those properties in your use case, you know in advance that you’ll need that data so you might as well retrieve it up front.
February 17th, 2008 at 10:04 am
Thanks!
March 14th, 2008 at 2:45 am
This solution promises to support lazy loading of NHibernate entities across the wire using WCF.
http://slagd.com/?p=4
March 14th, 2008 at 7:43 am
Well, as i mentioned before I really don’t think that’s a good idea… crossing the wire too much can be really expensive.
March 25th, 2008 at 9:48 am
This looks to be exactly what I am after, but when I open the attached project in VS2008, I get the following error on the ServiceWebHost project.
System.Runtime.InteropServices.ComException.
Any idea what could be causing this. Would it be possible to email me the project again?
I would be extremely grateful.
March 25th, 2008 at 9:52 am
the ServiceWebHost project hardly has code, and it certainly doesn’t use Interop directly… maybe there is a problem with your IIS installation/configuration? Can you host other WCF services without problems in IIS?
March 27th, 2008 at 10:20 pm
“First of all, this is just an example, that’s why the ISessionFactory is created within the service implementation, in a real system i wouldn’t do this.”
Out of interest, how would/do you do this? I’m having trouble right now deciding how best to accomplish this, particularly with regard to IoC using Windsor.
Cheers.
March 27th, 2008 at 11:08 pm
i’d go for a SessionProvider kind of class which would be responsible for configuring and initializing the ISessionFactory and for handing out ISessions to consumers. I wouldn’t use an IoC container to create the ISessionFactory because you’ll probably never use another implementation than the one NHibernate gives you anyway.
March 28th, 2008 at 11:40 pm
Thanks. That’s how I’m doing it now, more or less but I can think of at least one situation where I don’t want to hand out standard ISession objects – unit testing the service layer.
In that situation, I want something like an InMemorySessionFactory. That’s my big problem with WCF and NH at the moment – because the SessionFactory is so expensive – it needs to be created only the once, which in WCF means being a static. In this instance, how do you override the default implementation that the service uses?
It beats me.
March 29th, 2008 at 10:10 am
the NHibernate SessionFactory is completely thread-safe so there’s not really a problem with it being a static instance behind a service layer.
As for the unit testing, have you considered using an in-memory database to run your tests against? I’m not sure but i think NHibernate has support for SQLite.
April 7th, 2008 at 4:32 pm
[...] Sending NHibernate entities over the WCF wire « Davy Brion’s Blog [...]
April 9th, 2008 at 1:16 am
[...] Sending NHibernate entities over the WCF wire « Davy Brion’s Blog …By default, WCF services use the DataContractSerializer to serialize/deserialize types. But when you’re using NHibernate, you’re most likely using some of the persistent collection types and proxies. Some people just want to use the same types serv (tags: dev dotnet dataaccess nhibernate wcf ormappers) [...]
May 24th, 2008 at 12:45 pm
Is NetDataContractSerializer compatible with Compact Framework?
May 24th, 2008 at 1:01 pm
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.netdatacontractserializer.aspx
the compact framework isn’t listed among the supported .NET frameworks
June 4th, 2008 at 1:27 pm
Hi there,
I need to serialize / deserialize object to cml and since I am using nHibernate I have to use NetDataContractSerializer/DataContractSerializer.
I used the above code and put [UseNetDataContractSerializer] on the getters of the IList (which so far failed to serialize or deserialized as array when using UseNetDataContractSerializer. The serialize works OK now but when I deserialize I get the following exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> NHibernate.LazyInitializationException: Could not initialize proxy – no Session..
Any ideas? Not Really sure what to do.
Thanks
N
June 4th, 2008 at 1:46 pm
i’m not sure i follow what you’re trying to do but i think you just need to serialize/deserialize your nhibernate objects, without going through WCF services, right?
The [UseNetDataContractSerializer] is a custom attribute which modifies the behavior of a WCF OperationDescription. If you’re not using WCF, simply putting this attribute on your getters isn’t going to make a difference. Unless you modified the code of the attribute to do something completely different.
If you want to use the NetDataContractSerializer directly to serialize/deserialize your classes, you don’t need to use any attributes on the members of your classes. Just tag the classes themselves with [Serializable] and use the NetDataContractSerializer like you would normally use the XmlSerializer.
You can find more information on the NetDataContractSerializer here:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.netdatacontractserializer.aspx
June 4th, 2008 at 2:06 pm
Hi,
Yes.. I am only trying to serialize and deserialize objects but nHibernate keeps messing things.
Now i only have [Serializable] attributes on the classes (no DataContract, DataMember, UseNetDataContractSerializer) and I am still getting the following error when I deserialize:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> NHibernate.LazyInitializationException: Could not initialize proxy – no Session..
Also i am not that sure that the object is serialized correctly as when I look at the xml it does not contain a value of a string property the object instance had.
BTW – when I tried to follow the example from msdn using IExtensibleDataObject I got an error that the nHibernate proxies do not implement IExtensibleDataObject.
Do you have any idea how I can simply serialize/deserialize without nHibernate messing everything (and with IList deserialized into Ilist and not arrays).
Many thanks!!
N
June 4th, 2008 at 2:20 pm
well, if you try to access a proxied object or proxied collection outside of the scope of the session, then it’s normal to get that exception. When you deserialize the object, it’s a different instance than the original one so it’s not connected to the session.
Are you accessing any proxied objects or proxied collections within your object in code that could be touched during deserialization? Depending on how the NetDataContractSerializer sets the data (through setters for instance), it could trigger code that would access contained proxies which could cause that exception.
June 4th, 2008 at 3:19 pm
I don’t touch the proxies…they are accessed during serializtion – it doesn’t get to the deseralization.
When I use the sample from MSDN with IExtensibleDataObject i cannot serialize and get an error that the nHibernate proxies do not implement IExtensibleDataObject.
When I use NetDataContractSerializer as is without adding anything (except [Serializable]) then it is serializes but I get the session error when deserialize.
the only thing that worked was DataContractSerializer but then Ilist was deserialized as arrays.
So I am quite lost. I don’t know what to do to get it to work….I am actually thinking of using Linq cos I cannot make the nHibernate to work along with serialization…
Any ideas? The IDataContractSurrogate made DataContractSerializer work… Is there anything simlilar for NetDataContractSerializer?
June 4th, 2008 at 3:26 pm
In my previous post – ignore the first line – I meant to say that I am not touching the proxies…
June 4th, 2008 at 3:44 pm
no idea about the IDataContractSurrogate… or IExtensibleDataObject for that matter
like i said, the only thing i can think of is code in your objects that’s triggered during the deserialization which accesses the proxies. If that’s not it, i can’t help you i guess…
June 4th, 2008 at 5:17 pm
I agree.. this code is triggered.. but I just don’t know how to workaround it and also how to workaround the problem with the session (as the nHibernate will alway require valid session..) …
Thanks anyway
March 6th, 2009 at 3:32 pm
Hello
I dowloaded the sample and compiled it.
The domain and nHibernate sections work, but when running the WCF client ( Web or Console ) I get the following Exception
{“Object of type ‘Iesi.Collections.Generic.HashedSet`1[Northwind.Domain.Entities.Employee]‘ cannot be converted to type ‘Iesi.Collections.Generic.ISet`1[Northwind.Domain.Entities.Order]‘.”}
Like it is trying to assign an employee object to an Order.
what can be going wrong ?
March 6th, 2009 at 3:35 pm
Al litle more detail,
the exception occurs when calling
IList customers = proxy.GetCustomersWithTheirOrders();
I debug insîde the Service and it read the information right. ( 1 Order with 2 Lines )
The exception type is System.ArgumentException
The stack Trace is as follows
“\r\nServer stack trace: \r\n at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)\r\n at System.Reflection.RtFieldInfo.InternalSetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture, Boolean doVisibilityCheck, Boolean doCheckConsistency)\r\n at System.Reflection.RtFieldInfo.InternalSetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture, Boolean doVisibilityCheck)\r\n at System.Runtime.Serialization.FormatterServices.SerializationSetValue(MemberInfo fi, Object target, Object value)\r\n at System.Runtime.Serialization.FormatterServices.PopulateObjectMembers(Object obj, MemberInfo[] members, Object[] data)\r\n at Castle.DynamicProxy.Serialization.ProxyObjectReference.RecreateClassProxy(SerializationInfo info, StreamingContext context)\r\n at Castle.DynamicProxy.Serialization.ProxyObjectReference.RecreateProxy(SerializationInfo info, StreamingContext context)\r\n at Castle.DynamicProxy.Serialization.ProxyObjectReference..ctor(SerializationInfo info, StreamingContext context)\r\n at ReadProxyObjectReferenceFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n at ReadOrderFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n at ReadArrayOfanyTypeFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString , XmlDictionaryString , CollectionDataContract )\r\n at System.Runtime.Serialization.CollectionDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadSerializationInfo(XmlReaderDelegator xmlReader, Type type)\r\n at ReadArrayOfKeyValueOfanyTypeanyTypeFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n at ReadCollectionEntryFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n at ReadPersistentGenericSetOfOrderSwFpc1QfFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n at ReadCustomerFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n at ReadArrayOfCustomerFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString , XmlDictionaryString , CollectionDataContract )\r\n at System.Runtime.Serialization.CollectionDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n at ReadArrayOfCustomerFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, Int32 declaredTypeID, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, String name, String ns)\r\n at System.Runtime.Serialization.NetDataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName)\r\n at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName)\r\n at System.Runtime.Serialization.NetDataContractSerializer.ReadObject(XmlDictionaryReader reader, Boolean verifyObjectName)\r\n at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)\r\n at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameter(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)\r\n at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)\r\n at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)\r\n at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeReply(Message message, Object[] parameters)\r\n at System.ServiceModel.Dispatcher.ProxyOperationRuntime.AfterReply(ProxyRpc& rpc)\r\n at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)\r\n at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)\r\n at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)\r\n at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)\r\n at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)\r\n\r\nException rethrown at [0]: \r\n at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)\r\n at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)\r\n at ServiceInterface.ICustomerService.GetCustomersWithTheirOrders()\r\n at ServiceClient.Program.Main(String[] args) in C:\\Projects\\NHibernate\\WCF\\NhibernateAndWcf\\ServiceClient\\Program.cs:line 16\r\n at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)\r\n at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)\r\n at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()\r\n at System.Threading.ThreadHelper.ThreadStart_Context(Object state)\r\n at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n at System.Threading.ThreadHelper.ThreadStart()”
March 6th, 2009 at 3:52 pm
Andres,
i got the same exception sometimes, but i think i only got it when i was hosting the service both through IIS and the Console host… not sure though
either way, this entire approach of sending detached NHibernate entities over WCF is something i no longer recommend… i prefer to keep my NHibernate entities inside the service layer, and send specific DTO’s over WCF
April 7th, 2009 at 4:34 pm
Davy > I’m thinking about using DTO’s too because I’m getting totally frustrated with sending my entities over the wire. I have issues with proxy classes and also NH specific types which are not serialized by WCF.
Anyway I wanted to know how you manage to persist your DTO’s to the database with NH ? I want to do the following :
Load business model entity with NHibernate
Convert business model entity to dto (by just keeping the properties I need)
Client modifies dto and send it back to the server
Server convert dto back to business model entity
NH persists business model entity to database.
But there’s a problem : Since the dto is a smaller version of the business model entity, that means when I re-create my entity on the server side, it’s not going to be a full-feature entity, so how NHibernate is going to figure out what to save ? It’s probably going to interpret that as many properties have changed (when in fact they haven’t) and persists wrong data in the DB.
You insight would be appreciated.
April 7th, 2009 at 4:50 pm
when you get back into your service layer, just retrieve the object from the database again and modify the properties you need/want to update
April 8th, 2009 at 8:18 pm
Somebody else gave me the same advice. It seems to be the way to go. It costs a SELECT but I guess it’s not too much of an issue, and NHibernate makes it real easy anyway.
Thanks a lot !
June 30th, 2009 at 11:59 am
Hi,
I am trying to access the WCF service having following interface and implementation:
[ServiceContract(Namespace="http://SMS.com/OPS")]
public interface IOrderProcessingService
{
[UseNetDataContractSerializer]
[OperationContract]
Customer GetAnyCustomer();
[UseNetDataContractSerializer]
[OperationContract]
Customer GetCustomerByName(string customerName);
}
public class OrderProcessingService : IOrderProcessingService
{
public Customer GetAnyCustomer()
{
ICustomerRepository repository = new CustomerRepository();
return repository.GetByName(“Tom”);
}
public Customer GetCustomerByName(string customerName)
{
ICustomerRepository repository = new CustomerRepository();
return repository.GetByName(customerName);
}
}
CustomerRepository class is accessing the database using NHibernate.
Now the problem is that the method GetAnyCustomer() is working fine. But when the service client is accessing the method GetCustomerByName, the following exception is thrown, indicating that there is some problem in deserializing the given string parameter customerName. The exception details are as follows:
WorkingWithGraph.Tests.OrderProcessingServiceTest.GetCustomerByNameTest : System.ServiceModel.FaultException : The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://SMS.com/OPS:customerName. The InnerException message was ‘Error in line 1 position 281. XML ‘Element’ ‘http://SMS.com/OPS:customerName’ does not contain expected attribute ‘http://schemas.microsoft.com/2003/10/Serialization/:Type’. The deserializer has no knowledge of which type to deserialize. Check that the type being serialized has the same contract as the type being deserialized.’. Please see InnerException for more details.
And what does it meant by : XML ‘Element’ ‘http://SMS.com/OPS:customerName’ does not contain expected attribute ‘http://schemas.microsoft.com/2003/10/Serialization/:Type’
I have also tried encapsulating the customerName both in a DataContract and in a MessageContract and used these contracts as parameter types, but not to avail anything.
Please help me.
Thanks in advance.
Gaurav
October 23rd, 2009 at 11:40 am
Nice! Thanks a lot.
December 7th, 2009 at 6:42 am
Hello,
I made silverlight 3 + Silverlight enabled WCF service + NHibenate application.
I write two contract methods. First contract methods works fine .. but when I call second method it gives me exception that “The remote server returned an error: NotFound.” in referance.cs fil..
why this happened ..
pls help me.. I spend a lot time to solve this problem ..