Tim Scott's Blog

May 9, 2007

Remoting Using WCF and NHibernate

Filed under: C#, NHibernate, WCF — Tim Scott @ 5:00 am

By Tim Scott and Greg Banister

UPDATE – 3/5/09 – There is ongoing discussion in the community over remoting versus a service oriented architecture (SOA).  Almost two years after its publication this post continues to to get a lot of traffic, and so we feel it’s appropriate to add a small comment with our opinion on the matter.   We generally do not recommend remoting (sending domain objects over the wire), and would in almost all cases today, prefer an SOA approach. This article shows how we solved a specific technical problem in implementing a smart client application using a remoting architecture.   It has value on that basis.

Introduction

Windows Communication Foundation (WCF) is Microsoft’s unified messaging framework for building distributed applications. It is targeted at two types of applications:

  • distributed objects applications
  • service oriented applications (SOA)

Let’s define what we mean by each. “Distributed objects applications” are applications where client and service share common custom business object types and pass these objects back and forth over the wire. Conversely, SOAs typically hide business object types and pass lighter data transfer objects between client and service. Microsoft intends for WCF to supersede ASMX Web Services for SOA applications and .NET Remoting for distributed objects applications.

NHibernate is a port of Hibernate, the popular open source object‑relational mapper for Java. NHibernate has been gaining popularity in the .NET world, and we are avid users. As we will discuss in this article, it is possible to build a distributed objects application using WCF for messaging and NHibernate for object persistence. But to pull this off you have to know some tricks. As one wades into the WCF waters, one discovers that WCF has a lot of tricks. Articles and samples abound for WCF, but we could find none that address the issues that we faced. In this article we will share what we learned.

The Application

In early 2006 our team committed to create a “smart client” application using WCF for communications between a WinForms client and a Web service. Client and service would contain a common business domain assembly and would pass business objects back and forth. We also decided to use NHibernate for object persistence. This sounded great on paper, and after a little hacking we got it to work, or so we thought.

As we prepared to develop this application, we studied many WCF articles and “getting started” examples. We even created a “spike” application using WCF together with NHibernate. Based on all this research we made dozens of explicit configuration choices. We made many more choices by default.

The Problem

One such default choice was to use the DataContractSerializer. Only much later did we learn that Microsoft recommends the DataContractSerializer specifically because it assumes the client knows nothing of .NET types. This keeps coupling between client and service loose and so maximizes cross‑platform interoperability. The DataContractSerializer, we realized at long last, was the problem.

So why was it the problem? In a word, collections. Complex business objects typically have collections (e.g., Order has LineItems). One thing we love about NHibernate is how nicely it handles persistent collections. It provides various custom collection types that implement IList. We use the NHibernate Bag for all of our collections. Bag contains several properties that help NHibernate detect changes to collections and persist them properly. By using some clever versioning techniques, NHibernate always knows which members of collections to insert, update and delete any time you save its parent object.

As an aside, NHibnerate has other choices for collections besides Bag. There are Sets, Lists, Maps, Arrays, SortedSets, SortedMaps and IdBags, all of which, like Bag, inherit from NHibernate.Collection.PersistentCollection. This article addresses only the Bag type. We would guess the same problems and solutions apply to these other types as well; however, we have not used these types, so we cannot say for sure.

Back to the DataContractSerializer. It is capable of serializing custom objects. To accomplish this you simply decide which classes and class members to share and decorate them with DataContract attribute and DataMember attribute respectively. If the class members are not primitive types, you can further decorate your classes with KnownType attributes. This attribute tells WCF that both sender and receiver understand the custom type. Here is an example of a Company class decorated for WCF:

[DataContract]
[KnownType(typeof(NHibernate.Collection.Bag))]
[KnownType(typeof(NHibernate.Impl.CollectionEntry))]
[KnownType(typeof(CompanyRole))]
[KnownType(typeof(Person))]
public class Company : IEntity
{
    [DataMember]
    private Guid id;
    private string name;
    [DataMember]
    private IList employeesList;   

    public Guid Id
    {
        get { return id; }
    }   

    [DataMember]
    public string Name
    {
        get { return name; }
        set { name = value; }
    }   

    private IList EmployeesList
    {
        get
        {
            if (employeesList == null)
            {
                employeesList = new ArrayList();
            }
            return employeesList;
        }
        set { employeesList = value; }
    }   

    public Person[] Employees
    {
        get
        {
            Person[] employees = new Person[EmployeesList.Count];
            EmployeesList.CopyTo(employees, 0);
            return employees;
        }
    }   

    .
    .
    .   

}

When NHibernate fetches a Company from the database, employeesList will be a Bag of Persons. We assumed that by setting Bag as a known type, WCF would properly handle employeesList. However, even with the KnownType attribute, DataContractSerializer does not properly handle NHibernate Bags. The employeesList enters the serializer as a Bag and comes out the other end as an object array. Before serialization:

bag.jpg

After serialization:

objectgraph.jpg

The following test further illustrates the problem:

[TestMethod]
public void DataContractSerialization_will_change_the_type_of_a_Collection()
{
    Company company = GetCompanyFromNhibernate();   

    //company.EmployeesList made public for the purpose of this demo
    Assert.AreEqual(typeof(NHibernate.Collection.Bag), company.EmployeesList.GetType());   

    List<Type> knownTypes = new List<Type>();
    knownTypes.Add(typeof(Person));
    knownTypes.Add(typeof(NHibernate.Collection.Bag));
    knownTypes.Add(typeof(NHibernate.Impl.CollectionEntry));
    DataContractSerializer serializer = new
             DataContractSerializer(typeof(Company),knownTypes);   

    //serialize company to a memory stream
    Stream stream = new MemoryStream();
    serializer.WriteObject(stream,company);   

    //deserialize the memory stream back to a company
    stream.Position = 0;
    company = (Company) serializer.ReadObject(stream);   

    Assert.AreNotEqual(typeof(NHibernate.Collection.Bag), company.EmployeesList.GetType());
    Assert.AreEqual(typeof(object[]), company.EmployeesList.GetType());
}

One might expect that NHibernate to blow up when it encounters a persisted collection that has morphed into a simple object array. Not so! After a small hack that we created, NHibernate was able to persist updates and inserts just fine. However, it was not able to figure out deletions. Rather than deleting an item that had been removed from the collection, it simply de‑referenced it. That is, it updated the foreign key to its parent (in the preceding example, CompanyID) to NULL. These de-referenced items end up as orphaned records in the database. In our case, for certain collections, the result was hundreds of thousands of orphans.

The Solution

We recall vividly the moment we discovered this problem. Once we stopped sobbing uncontrollably, we pressed on and worked out a solution (sort of). We added a bunch of tricky code to our persistence layer to detect orphans and delete them from the database. We’ll not belabor the point by explaining this complex hack; suffice it to say it was both ugly and inefficient!

Then one day, almost by accident, we found the NetDataContractSerializer. Actually we had known about it, but we hadn’t grasped what it was. The NetDataContractSerializer, unlike its brother the DataContractSerializer, serializes .NET type information. To use it both client and server must understand .NET types. Cross‑platform interoperability is lost, which was fine in our case. Our client and service are by nature tightly coupled – they share a business domain.

So we gave the NetDataContractSerializer a try. To our delight it serialized NHibernate Bags just fine. Problem solved! The following test illustrates:

[TestMethod]
public void NetDataContractSerialization_will_Not_change_the_type_of_a_Collection()
{
    Company company = GetCompanyFromNhibernate();   

    //company.EmployeesList made public for the purpose of 
    //this demo
    Assert.AreEqual(typeof(NHibernate.Collection.Bag), company.EmployeesList.GetType());   

    NetDataContractSerializer serializer = new NetDataContractSerializer();   

    //serialize company to a memory stream
    Stream stream = new MemoryStream();
    serializer.Serialize(stream, company);   

    //deserialize the memory stream back to a company
    stream.Position = 0;
    company = (Company)serializer.Deserialize(stream);   

    Assert.AreEqual(typeof(NHibernate.Collection.Bag),company.EmployeesList.GetType());
    Assert.AreNotEqual(typeof(object[]), company.EmployeesList.GetType());
}

Soon we learned that NetDataContractSerializer solved other problems too. From the start we had wanted to pass generic types between client and service. We could not figure out how to do this using DataContractSerializer. Again, KnownType attributes did not seem to work. There might be some way to do it, but we did not find it. No matter, NetDataContractSerializer handles .NET generic types just fine.

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.

Using NetDataContractSerializer

Unfortunately you cannot simply flip a config switch and change serializers. You need to write some code. We created two classes, like so:

public class NetDataContractOperationBehavior : DataContractSerializerOperationBehavior
{
    public NetDataContractOperationBehavior(OperationDescription operation)
        : base(operation)
    {
    }   

    public NetDataContractOperationBehavior(OperationDescription operation, DataContractFormatAttribute dataContractFormatAttribute)
        : base(operation, dataContractFormatAttribute)
    {
    }   

    public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns,
        IList<Type> knownTypes)
    {
        return new NetDataContractSerializer(name, ns);
    }   

    public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name,
        XmlDictionaryString ns, IList<Type> knownTypes)
    {
        return new NetDataContractSerializer(name, ns);
    }
}   

public class UseNetDataContractSerializerAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
    {
    }   

    public void ApplyClientBehavior(OperationDescription description,
        System.ServiceModel.Dispatcher.ClientOperation proxy)
    {
        ReplaceDataContractSerializerOperationBehavior(description);
    }   

    public void ApplyDispatchBehavior(OperationDescription description,
        System.ServiceModel.Dispatcher.DispatchOperation dispatch)
    {
        ReplaceDataContractSerializerOperationBehavior(description);
    }   

    public void Validate(OperationDescription description)
    {
    }   

    private static void ReplaceDataContractSerializerOperationBehavior( OperationDescription description)
    {
        DataContractSerializerOperationBehavior dcsOperationBehavior =
        description.Behaviors.Find<DataContractSerializerOperationBehavior>();   

        if (dcsOperationBehavior != null)
        {
            description.Behaviors.Remove(dcsOperationBehavior);
            description.Behaviors.Add(new NetDataContractOperationBehavior(description));
        }
    }
}

Then in the service contract, to every method we added the UseNetDataContractSerializer attribute, like so:

[UseNetDataContractSerializer]
[OperationContractAttribute]
Company SaveCompany(CompanyUpdater companyUpdater);

NOTE: We derived the code to use NetDataContractSerializer from code examples we found on the web:

Conclusion

Our specific conclusion is, to serialize objects with NHibernate Bags using WCF, use the NetDataContractSerializer. A more general conclusion might be, if you want to distribute custom business objects between a .NET client and WCF service only, such as with a distributed objects application, use NetDataContractSerializer unless there is some compelling reason not to.

About these ads

36 Comments »

  1. What a fantastic exploration of advanced serialization techniques in WCF. I think that ORM is still a viable approach behind the service and if interoperability is not a design goal, this approach looks awesome!

    I do think it would be interesting to explore some of the “hacks” you mentioned for handling deletions behind the service however as I think that there is a strong case for being able to deliver SOA applications with the speed that NHibernate facilitates while still maintaining at least WS-I Profile interop. Maybe a part 2?

    Comment by Rick G. Garibay — May 9, 2007 @ 8:48 pm

  2. private IList EmployeesList
    {
    get
    {
    if (employeesList == null)
    {
    employeesList = new ArrayList();
    }
    return employeesList;
    }

    return employeesList ?? new ArrayList();

    Comment by Eber Irigoyen — May 26, 2007 @ 11:38 pm

  3. I meant

    return employeesList ?? employeeList = new ArrayList();

    Comment by Eber Irigoyen — May 26, 2007 @ 11:39 pm

  4. Eber, I agree, that’s more concise. Some people don’t like that syntax, but I do.
    Incidentally, this is somewhat of an old pattern. In this app, we exposed all our collections as arrays so they would be strongly typed and also prevent calling Add, Remove methods directly.
    Today we would expose this this as a generic List and return it AsReadOnly. Generics rock!

    Comment by Tim Scott — May 26, 2007 @ 11:55 pm

  5. First off: awesome post. I’ve been looking for something like this for a while.

    We have essentially the same exact setup you describe; custom business objects that are shared across client and server. We’ve been using LLBLGenPro for our OR/M and then mapping between its custom entity classes and our business objects prior to sending them over the wire.

    Then we decided to try NHibernate. I wanted to eliminate the mapping from LLBL entity types to our business objects and just have an OR/M that mapped directly to our business objects and could persist them wisely. Unfortunately, we ran into some of the same issues you did. But in addition to serialization issues, we ran into some session issues with NHibernate and never could get it to work correctly. Sadly, we had to abandon NHibernate for the time being.

    I’d love to see how you guys have NHibernate and your server configured in your distributed scenario. This seems like such a common issue. Thanks again for the post!

    Comment by Chris Holmes — May 27, 2007 @ 2:45 am

  6. Nice post. I’ve learned some must know things about using NHibernate in combination with WCF. Thanks.

    Comment by Mark Monster — May 27, 2007 @ 10:06 am

  7. Nice post by the way, but i have a slightly different problem. I’m trying to serialize using DataContractSerializer, but it gives me a CProxy exception, because of Data Contract and Data Member as we have to put explicitly the KnownType attribute, and it seems that serializer doesn’t know the proxy object(I’m using lazy loading by the way). Is there any way to give some knowledge to the datacontract to treat the proxy object as a real object?

    Comment by Saydios — May 28, 2007 @ 3:33 am

  8. Won’t work in all cases:
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1354591&SiteID=1

    Object graph to XML and back is tricky, especially with interfaces and cyclic references. It’s also odd to use XML in that case, especially since an optimized remoting serializer (which we’ll release soon for llblgen pro) is more fitted for this approach, as you’re using .NET types on client AND server anyway and can get you much higher throughput.

    XML as a transport format looks nice on paper, but it’s not meant to be used as the format for object graphs. Better is to use another format to serialize/deserialize object graphs and use XML based services on a higher level in your application, like you should with any service: build it with a proper interface and as an atomic application. See the recently posted Gregor Hophe’s video at InfoQ for a guidance on this.

    Comment by Frans Bouma — May 28, 2007 @ 10:43 am

  9. Saydios,

    I’m not sure I totally understand your post, but I’ll try to answer what I think it may be saying.

    When you say you’re getting a “CProxy” exception, is that refereing to the Castle.DynamicProxy? You may have a problem using Lazy Loading, because I’d guess that the act of serializing your lazy collection will not trigger DynamicProxy to load the collection before it’s serialized. In our app, we were forced to dispense with lazy loading entirely the moment we decided to send collections over the wire. Because, of course, you couldn’t expect the lazy loading to work even if you did get the DynamicProxy to serialize and deserialize correctly. That would be a neat trick if you could.

    Greg

    Comment by Greg Banister — May 30, 2007 @ 12:50 am

  10. This is not a solution in the general case… You are exposing your data access classes in your service? That’s not acceptable to us. If you add a column to your database then your service contract changes. Not acceptable. We map data classes to business classes. I’m not sure why you wanted to get rid of the mapping, it’s there for a reason. How can we handle object state when going through a mapping layer? It doesn’t seem possible.

    Comment by Greg #2 — June 4, 2007 @ 2:44 pm

  11. I don’t understand this last comment. I don’t understand how the data acceess classes are exposed here. We do use the NHibernate mapping files to map our entities to tables in the database. If we add column to the database that we want represnted in one of our entities, then we add the property or whatever to the map and the entity and we’re golden. Please clerify if I’m missing something.

    Greg

    Comment by Greg Banister — June 9, 2007 @ 10:26 pm

  12. I’ve been working through this (thanks for the nice post) but I am getting WCF errors:

    “System.IO.FileNotFoundException occurred
    Message=”Could not load file or assembly ‘DynamicAssemblyProxyGen, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.”
    Source=”mscorlib”
    FileName=”DynamicAssemblyProxyGen, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null””

    When I am trying to serialize a business domain entity mapped via NHibernate using your technique as described above.
    It looks like this is thrown on the client – even when the Castle.DynamicProxy assembly is added is as a reference to the project.

    Googled that error and it points at one post somewhere we they were having issues – and they were looking at the signing of the Castle.DynamicProxy.

    Is this something you went through? As I am about to rebuild the source code of both Castle.DynamicProxy & NHibernate to try and get versions that I can use over WCF? Something seems very wrong – with the concept of having to re-sign those projects… I have missed something – but I am not sure what…

    any ideas?
    Thanks
    Todd

    Comment by Todd — July 3, 2007 @ 5:04 pm

  13. KnownTypeAttribute is used to tell the DataContractSerializer about class hierarchies.

    For example:

    [DataContract]
    [KnownType(typeof(Derived))]
    public class Base
    {
    }

    [DataContract]
    public class Derived
    {
    }

    Now you can use the class Derived everywhere in a WCF service contract a Base is allowed. If you didn’t annotate the base class with the KnownTypeAttribute this wouldn’t have been possible.

    Comment by Sonix — July 9, 2007 @ 1:26 pm

  14. I’ve been dealing with a lot of the same issues:

    service layer
    ———-
    business objects & logic
    ———–
    dal (nhibernate & sqlcommand stuff)
    ———–
    sql 2005

    Hibernate is great because you can exist in a very object oriented world in your business tier, and a lot of basic crud operations happen very quickly.

    Because of our service tier, we use Data Transfer Objects (DTO’s), which are hybrid versions of our real business objects. They’re optimized for wire transfer and xml serialization. They allow us to not butcher our business objects, which you otherwise need to do else you end up with circular reference problems and insanely large object graphs.

    The business objects, like Client, for example, have two Insert methods: one that takes the Client’s DTO, and another that takes a full fledged Client.

    We don’t need DTO’s for everything, and smart use of [System.Xml.Serialization.XmlIgnore] on some of your properties will make your life easier as well.

    We generally evict everything from the session when we grab it, and a lot of things also get hit with NHibernateUtil.Initialize(o), which force loads the object (all lazy loading happens).

    The biggest thing I would advocate is remembering that if you split your DAL out into a different assembly, and you’re using NHibernate, you are more than allowed to overload some of your crud operations, and handle certain class operations differently. In my case, we had a huge problem with deletes with NHibernate, and it was a documented error that they haven’t fixed yet. No problem, just handle that particular classes operations outside of NHibernate.

    Comment by Eric F Kaufman — August 16, 2007 @ 5:47 am

  15. This is excellent. Exactly what we’re trying to do. Out of interest, how are you handling the NHibernate Sessions in WCF?

    We have a previous application using ASP.NET web services and we used the framework from this article on codeproject http://www.codeproject.com/aspnet/NHibernateBestPractices.asp?df=100&forumid=278860&fr=101

    However it seems that using HttpContext.Current is no longer applicable. Also it uses an HHTPModule to start and end a session automatically for each request.

    Thanks,
    Chris

    Comment by Chris — November 8, 2007 @ 4:30 pm

  16. Chris,
    At that time, we implemented our own Unit Of Work Pattern to manage session, however, now I would recommend Rhino.Commons.UnitOfWork and Rhino.Commons.Repository for managing session. In our WCF Web Service, we stuck session in Thread Local Storage, but that may not be the most performant solution. Instead, it may be better to use OperationContext.Current.InstanceContext.Extensions.

    Greg

    Comment by Greg Banister — November 8, 2007 @ 6:56 pm

  17. Thanks,

    I’ve now changed it to use OperationContext.Current.InstanceContext.Extensions to store the transaction and session. And am using the OperationContext.Current.OperationCompleted event to close the session. This keeps it quite simple. However will look at the the Rhino.Commons stuff when I have a bit of time – it looks very interesting.

    Thanks for your suggestions,
    Chris

    Comment by Chris — November 13, 2007 @ 10:05 am

  18. Hi,
    I am Implementting the solution above, but it doesn’t work.
    I impplemented the NetDataContractSerializer
    well it works but there is no data when I call the wcf method.
    I made a test with DataContractSerializer and it happens a cproxy error. and It is obvios…because he doesn’t recognize the cproxy type because of the lazy loading… may I have to disable the lazy loading for all the DTO objects?? to make it work?.. doesn’t it affect the performance ??..

    Comment by jefferson — November 15, 2007 @ 10:53 pm

  19. jefferson.

    Quoting Greg above “we were forced to dispense with lazy loading entirely the moment we decided to send collections over the wire.” And yes, foregoing lazy loading can’t but impact performance. We have dealt with this by tracking how noticeable performance issues and working around them in various ways.

    You have mentioned the single biggest downside of remoting with and Nhib backend. It would be awesome if someone could come up with some solution for “remote laziness!”

    Tim

    Comment by Tim Scott — November 15, 2007 @ 11:17 pm

  20. Hi Tim, thanks for your reply, I have been looking for a solution for the proxy serialization and I found one in spanish so interisting… and I think is the way of solving this without disable the lazy loading.. here is the link, the Idea is using reflexion for unproxy the proxies…and make it work… I haven’t implemented yet, here is the page and the code:
    http://knocte.blogspot.com/2006/12/serializacin-binaria-con-nhibernate.html

    you can help me with the solution and make it work…

    thanks…!

    Comment by jefferson — November 16, 2007 @ 2:02 pm

  21. Hi Tim,

    Is there a place where we can download your test application?

    Best regards,

    Luc

    Comment by Luc — December 19, 2007 @ 3:31 pm

  22. Luc,

    Sorry there is no test application. This article is about a real application, and the examples (with slight modifications to protect the innocent) are from the real application.

    Comment by Tim Scott — December 19, 2007 @ 4:45 pm

  23. IDataContractSurrogate can solve the NHibernate serialization problems while at the same time providing interoperability. The IDataContractSurrogate can be used to basically unproxy and unpersist any NHibernate entity. It isn’t really that much code either.

    I am serializing by hand so I don’t know how it would work with WCF, but I am sure there has to be a way to set a surrogate when serializing.

    I am going to post on it soon, but if you want to check it out just email me.

    Comment by Brian Hartsock — December 31, 2007 @ 9:07 pm

  24. I put up an example that uses this approach on my blog. Includes the full solution so you can download it and experiment with it. You can get it here:
    http://ralinx.wordpress.com/2008/01/03/sending-nhibernate-entities-over-the-wcf-wire/

    Comment by Davy Brion — January 3, 2008 @ 2:17 pm

  25. very interesting.
    i’m adding in RSS Reader

    Comment by music — January 7, 2008 @ 11:25 pm

  26. I haven’t investigated this yet, but check out NHibernate.Remote here:
    http://slagd.com/?p=4

    Comment by Oran — March 14, 2008 @ 2:08 am

  27. I’m sending Hibernate (NHibernate objects) over the wire using stardard DataContractSerializer, and they are really exposed over NetTcpBinding and BasicHttpBinding (web service actually). I had to implement a lot of code of course to extend service side and implement some helper classed, but any hibernate objects are always serialized and transferred.

    Maybe I will write an article about this a bit later.

    Comment by Ivan Gavrilyuk — April 9, 2008 @ 12:57 pm

  28. I’m trying to get this to work with a tree structure. But alas alack no luck…
    The serializer test is working and it serializes the children with no problem but over the wire I lose them for reasons unknown. I can see in to the collection but it is empty…All other collections in the object are coming through no problem at all just the children not… Any one with any bright ideas why or how. I dont think I need to implement that functionality anyway so its more of an academic question really just would like to know….!?

    Heres my code,
    [Serializable]
    [DataContract]
    [KnownType(typeof(NHibernate.Collection.Generic.PersistentGenericSet))]
    [KnownType(typeof(Iesi.Collections.Generic.HashedSet))]

    [KnownType(typeof(ItemHierarchyLevel))]
    [KnownType(typeof(Item))]
    public class ItemHierarchy:IItemHierarchy
    {
    [DataMember]
    public virtual Guid Id { get; set; }
    [DataMember]
    public virtual string Name { get; set; }

    public virtual ItemHierarchy Parent { get; set; }
    [DataMember]
    public virtual ISet Children { get; set; }
    [DataMember]
    public virtual ItemHierarchyLevel HLevel { get; set; }
    [DataMember]
    public virtual Item ItemNumber { get; set; }
    [DataMember]
    public virtual ISet ItemBaseProps { get; set; }
    public ItemHierarchy()
    {
    Children = new HashedSet();
    ItemBaseProps = new HashedSet();
    //ItemNumber = new Item();
    }

    public virtual void AddChildItemHierarchy(ItemHierarchy child)
    {
    Children.Add(child);
    child.Parent = this;
    }

    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
    }
    }
    And this test is ok, with the count of children being correct…

    [Test]
    public void NetDataContractSerialization_will_Not_change_the_type_of_a_Collection()
    {
    ItemHierarchy ith = _repository.GetAggregateByName(“Top”);
    Assert.AreEqual(typeof(NHibernate.Collection.Generic.PersistentGenericSet), ith.ItemBaseProps.GetType());

    NetDataContractSerializer serializer = new NetDataContractSerializer();

    //serialize company to a memmory stream
    Stream stream = new MemoryStream();
    serializer.Serialize(stream, ith);

    //deserialize the memory stream back to a company
    stream.Position = 0;
    ith = (ItemHierarchy)serializer.Deserialize(stream);

    Assert.AreEqual(typeof(NHibernate.Collection.Generic.PersistentGenericSet), ith.ItemBaseProps.GetType());
    Assert.AreNotEqual(typeof(object[]), ith.ItemBaseProps.GetType());
    }

    Any ideas welcomed,

    Comment by alex — July 8, 2008 @ 9:20 am

  29. Hi, this is an interesting article which I’m sure will be usefull to me in the (near) future, since I’m playing with NHibernate & WCF as well to see what is possible when combining these 2 powers. :¨)

    However, right now, I’m facing another problem for which I’ve found no solution yet. As I see that a lot of people who have posted comments here which are using NHibernate in a remote scenario plz allow me to do so :).

    What I want to try to accomplish is -just as Tim Scott & Greg Banister did-, share my business objects on the client and on my remote service layer.
    This means that my ‘Customer entity’ for example is known by the client, and is known by the Service Layer.
    The problem that I am facing, is state tracking … Let me explain:
    Suppose I’ve a method in my remote service which allows me to get a Customer object.
    In my client app, I would call it like this:

    Customer c = RemoteProxy.GetCustomer (1);
    

    Then, as soon as I’ve retrieved the Customer, the user could make some changes to this Customer object. Or, he could also choose not to change properties on the object.
    Anyway, when the user click’s OK, I need to be able to determine if the user has changed, so that I do not unnecessarily invoke the remote call to save the changes.
    Then, in my remote interface, I also need to determine whether the object has really changed, so that no unnecessary UPDATE’s are invoked in the DB. (This is also necessary since, when using an Interceptor which sets some audit-information (last updated date, last updated by …), we should have no wrong information in the DB).

    I’ve written a post about it on my weblog. Any idea’s of how to solve this problem, is very much appreciated.
    http://fgheysels.blogspot.com/2008/07/nhibernate-in-remoting-wcf-scenario.html

    How did you guys cope with this problem ?

    Comment by Frederik — July 29, 2008 @ 8:22 pm

  30. Hello,

    Thanks for the post, I’ve run into the same issue.

    What did you do on the client side to specify that you are using the NetDataContractSerializer ?

    If I don’t do anything the client throws the following exception :

    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

    More detailed :
    The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:pPostId. The InnerException message was ‘Error in line 1 position 123. XML ‘Element’ ‘http://tempuri.org/:pPostId’ 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.’.

    Comment by sam — April 7, 2009 @ 1:40 pm

  31. 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

    Comment by Gaurav — June 30, 2009 @ 10:13 am

  32. How do I apply the Attribute [UseNetDataContractSerializer]

    When using a proxy generated by svcutils ?

    I’ve tried to use a code to replace the behaviour in the client – but it doesn’t work (the deserializer looking from staff in the wrong places… – looking for on of my server entities in mscorlib) :
    foreach (OperationDescription desc in this.Endpoint.Contract.Operations)
    {
    DataContractSerializerOperationBehavior dcsOperationBehavior = desc.Behaviors.Find();
    if (dcsOperationBehavior != null)
    {
    int idx = desc.Behaviors.IndexOf(dcsOperationBehavior);
    desc.Behaviors.Remove(dcsOperationBehavior);
    desc.Behaviors.Insert(idx, new NetDataContractOperationBehavior(desc));

    }
    }

    Comment by Dani — October 15, 2009 @ 2:16 pm

    • I have a similar problem to both that expressed by Dani and Sam above. Any solutions?

      Comment by Kevin Burton — December 4, 2009 @ 4:19 pm

  33. Great article, thanks a lot!

    Comment by Stephan — December 24, 2009 @ 9:29 am

  34. My classes are :

    [Serializable]
    public class Activity : ISerializable
    {
    public virtual int Id { get; set; }
    public virtual string Code { get; set; }

    public virtual IList CustomerList { get; set; }
    }

    [Serializable]
    public class Customer : ISerializable
    {
    public virtual int Id { get; set; }
    public virtual int ActivityId { get; set; }
    public virtual string Name { get; set; }

    public virtual Activity Activity { get; set; }
    }

    And my web service is:

    [WebMethod]
    public List AllCustomersInformations()
    {
    ISession session = NHibernateUtils.NhUtils.Session; // it works
    List CustomerListResult = (List)session.CreateCriteria().List(); // it works
    return CustomerListResult;
    }

    If I will change public List AllCustomersInformations() with public string AllCustomersInformations(), I will see the result. But I want to work public List AllCustomersInformations() I get some SOAP error.

    I try your solution but I didn’t. Can you help me?

    Comment by Captain — August 5, 2011 @ 1:30 pm

  35. With [UseNetDataContractSerializer] I no longer need to specify [KnownType].

    Thanks Tim and Greg!

    Comment by Tomasz Andraszek — September 12, 2012 @ 12:17 am


RSS feed for comments on this post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Shocking Blue Green Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: