These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 
Author Message
 Post subject: NHibernate & webservices
PostPosted: Wed Jun 28, 2006 9:32 am 
Newbie

Joined: Wed Mar 29, 2006 5:04 am
Posts: 9
Location: Antwerp, Belgium
After using NHibernate for a while, I started to use it, for a webservice. But I'm getting in trouble.
I have a Project-class, and an Employee-class. The Project-class has a property Employees that returns an IList of Employees. Lazy is set to true. The session closes as soon as I fetched my project.

I have a webmethod called GetProjects, which should return me the projects, but I only get exceptions. I'm pretty sure this is because The employees-collection is included in my SOAP-response, but since the session is closed, this does not work.

Has anyone already solved this problem ?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 28, 2006 11:19 am 
Beginner
Beginner

Joined: Thu Oct 16, 2003 7:30 am
Posts: 21
Location: Brussels
So what's the exception you are getting? Please also post your mapping files and the source of the Project and Employee classes if you expect any help.

Johan.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 28, 2006 1:16 pm 
Pro
Pro

Joined: Fri Nov 19, 2004 5:52 pm
Posts: 232
Location: Chicago, IL
One way to handle this problem would be to create an IHttpModule that closes your Session. i.e. you don't close your session manually, you let the HttpModule do it for you at the end of each request. I believe this gets run after the web method serializes your objects. I'm using the following code.

This goes in your Web.config file in the <system.web> section.

Code:
<httpModules>
  <add name="SessionModule" type="Common.Web.Persistence.SessionModule"/>
</httpModules>


This is the IHttpModule implementation. It assumes you have a helper class that manages your Session. This may not be the best implementation, but, it works for me.

Code:
using Common.Persistence;
using System.Diagnostics;
using System.Web;
using System.Web.SessionState;

namespace Common.Web.Persistence
{
    public class SessionModule : IHttpModule
    {
        private static TraceSource traceSource = new TraceSource("Common",
            SourceLevels.All);

        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.EndRequest += new System.EventHandler(context_EndRequest);
        }

        void context_EndRequest(object sender, System.EventArgs e)
        {
            HttpApplication ha = (HttpApplication)sender;
            string path = ha.Request.Path;
            if (path.EndsWith(".aspx") || path.EndsWith(".ashx")
                || path.Contains(".asmx"))
            {
                SessionManager.CloseSession();
            }
        }
    }
}


Another way to do it would be to use NHibernate.NHibernateUtil.Initialize() to initialize the collection before you close your Session manually.

You may also find that you have to set lazy="false" for all classes (not for collections, just classes). Otherwise, Castle.DynamicProxy will generate a proxy class and the proxy class that DynamicProxy generates does not have a no arg constructor and hence can't be XML serialized (I don't know why the authors of DynamicProxy don't just add a no arg constructor).


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 28, 2006 1:21 pm 
Pro
Pro

Joined: Fri Nov 19, 2004 5:52 pm
Posts: 232
Location: Chicago, IL
Another problem that you may run into is that if you're using the default encoding mechanism for web services, i.e. document/literal, it doesn't handle circular references, so, unless you use RPC encoding, you need to null out references in bidirectional relationships.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 30, 2006 2:30 am 
Newbie

Joined: Wed Mar 29, 2006 5:04 am
Posts: 9
Location: Antwerp, Belgium
Jemiller,

I think your solution would result in filling the employees-collection before sending my Project over the wire. But that's not what I want: I want my employees-collection to be empty. I want my get my employee-collection with a separate webmethod, when I need them.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 30, 2006 2:37 am 
Beginner
Beginner

Joined: Thu Oct 16, 2003 7:30 am
Posts: 21
Location: Brussels
In that case I guess the only solution is to explicitly set the employee collection to null before returning the project object from the webservice method because the XML serializer will try to access this collection and trigger the lazy loading. If you never intend to return the project object with all its empoyees from a web service, you might consider using the [XmlIgnore] attribute on the emplyee collection.

mvanwesemael wrote:
Jemiller,

I think your solution would result in filling the employees-collection before sending my Project over the wire. But that's not what I want: I want my employees-collection to be empty. I want my get my employee-collection with a separate webmethod, when I need them.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 30, 2006 2:50 am 
Pro
Pro

Joined: Fri Nov 19, 2004 5:52 pm
Posts: 232
Location: Chicago, IL
jandries has it right, null it out.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 30, 2006 2:54 am 
Newbie

Joined: Wed Mar 29, 2006 5:04 am
Posts: 9
Location: Antwerp, Belgium
Jandries,

I think the [XMLIgnore]-approach would be a good solution. (I thought there would be a tag like that, I just was too stupid to look in the XMLSerialisation-namespace).

Another alternative we thought about was to handle the onserializing-event, in which we could see if a collection was already initialised, and if not set the xmlignore.But that would require writing NHibernate-specific code in our businessclasses, which we don't want (leaking of concerns)).

neig bedankt.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 03, 2006 7:43 am 
Newbie

Joined: Wed Mar 29, 2006 5:04 am
Posts: 9
Location: Antwerp, Belgium
I'm still having problems here :

I've labeled the Employees-property with the xmlIgnore-attribute. So when calling the GetProject-webmethod I get my Project without my employees, as I wanted. I tried to create another webmethod similar to this :

Public Employees GetEmployees(Project project)
{
_session.Lock(project, LockMode.None);
return project.Employees;
}

Normally this would work fine, but not in my case: since employees is xmlIgnore, there is no employees-info send across the wire when calling the getemployees()-webmethod. Therefore project.Employees==null and NHibernate thinks that the employees-collection has already been initialised and does not go to the database to get my employees. Therefore my getEmployees-webmethod always return null. What am I missing here ?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 03, 2006 8:02 am 
Beginner
Beginner

Joined: Thu Oct 16, 2003 7:30 am
Posts: 21
Location: Brussels
NHibernate is not thinking anything at all in this example, as far as I can see. By specifying LockMode.None, you tell NHibernate that nothing about the project entity has changed, so project.Employees remains null and NHibernate does not intervene at all. Try changing LockMode.None to Read, or do an explicit query to get the employees (if the relationship is bi-directional).

Of zoiets.

Johan.

mvanwesemael wrote:
I'm still having problems here :

I've labeled the Employees-property with the xmlIgnore-attribute. So when calling the GetProject-webmethod I get my Project without my employees, as I wanted. I tried to create another webmethod similar to this :

Public Employees GetEmployees(Project project)
{
_session.Lock(project, LockMode.None);
return project.Employees;
}

Normally this would work fine, but not in my case: since employees is xmlIgnore, there is no employees-info send across the wire when calling the getemployees()-webmethod. Therefore project.Employees==null and NHibernate thinks that the employees-collection has already been initialised and does not go to the database to get my employees. Therefore my getEmployees-webmethod always return null. What am I missing here ?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 03, 2006 3:39 pm 
Pro
Pro

Joined: Fri Nov 19, 2004 5:52 pm
Posts: 232
Location: Chicago, IL
What you are missing is what you've already been told several times. Null the property out when you don't want it serialized, don't use XmlIgnore. If you do, it will never be serialized even in the case you want it to.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 03, 2006 10:08 pm 
Regular
Regular

Joined: Mon May 16, 2005 1:35 am
Posts: 67
You should probably consider using a different set of messaging classes (other than your domain classes) to serialize over the wire. Quite often, especially when your domain is complex, you want to serialize information that does not map directly (one-to-one) to your domain.

In your case for instance your object that would be serialized over the wire would not have an employees collection defined. You would use a series of translator objects to translate between your on-the-wire representation and your domain representation. With a complex domain, these translations can become rather complex. The more complex they get, the more benefit you draw from having a different representation for your on-the-wire messages as opposed to your domain classes.

Moreover, your domain classes are an implementation detail and it is not good practice in the services world to couple your service interfaces to their implementation. By definition, serializing your domain classes expose the service's implementation via its interface. This means that in the future, you will not easily be able to evolve your service implementation without breaking your service consumers.

Another consideration is that classes representing messages that are sent over the wire have different design constraints - such as version tolerance. By separating your message classes from your domain you can design each layer appropriately.

And finally, by having a separate set of messaging classes you avoid all the pitfalls of circular references, lazy initialization and serializing NH proxies. Dealing with these things in the long run can take longer than simply writing a new set of classes anyway.

I know the Hibernate team recommend against DTOs, describing it as an anti-pattern, but I don't agree this is true in the services world. Certainly when building a single Web application it is not necessary to create DTOs to interface with the presentation layer. But in the services world where many disparate applications need to evolve independently and communicate across many different platforms, the message is king and loose coupling is key, in which case DTOs become a necessity for all the reasons described above (and more).


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.