Sunday, 12 February 2012

Lazy loading WCF services.

Last day I had a discussion with Peter who works on an application that uses NHibernate as ORM and WCF as means of communication between client and server. The problem he was confronted with, in short, was a parent-child relation in his domain where the NHibernate mapping for the parent had a one-to-many relation to it's children but the child mapping didn't reference the parent. Now he needed to fetch all the children from a certain parent id, in a different WCF call for that matter, without first fecthing the parent. If you want the more elaborate version see here and for the solution he used see here and here.

Although he solved it quite nicely a different discussion sprouted from it. How would you develop a WCF service that returns a datacontract on which some members are lazy loaded over WCF and would you actually do this?
I remembered working on a project where they had some kind of mechanism that resembled it but the experience was rather unpleasant as they used their entities as DTO's which was ugly and caused all kinds of problems. Ah ... I think I just found the topic of my next post.

To answer the first question, how would you do it, well here's how I would do it.
The gist of it is to have your datacontract use a servicelocator or perhaps better an IoC containter to resolve the interface of the service contract that fetches the children. On the server the implementation of this interface could for example fetch the children from the database. On the client it would call the service responsable for fetching the children.

So let's have a look at the datacontract from the parent.

[DataContract]
    public class Parent
    {
        [DataMember]
         private IList<child> _children;

        public IChildServices ChildService

        {
            get { return ServiceLocator.SillyServiceLocator.GetInstance<ichildservices>(); }
        }

        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public String Name { get; set; }

        public IList<child> Children
        {
            get
            {
                if (_children == null)
                {
                    _children = ChildService.GetChildren(Id);
                }
                return _children;
            }
        }
    }
Note the "Children"-getter where we check if the children still have to be loaded and if so the service locator is queried for the implementation of the IChildServices and the GetChildren method is executed on it.

The implentation of the IChildServices on the client would look as folows.

public class ChildServicesProxy : ClientBase<ichildservices>, IChildServices
    {
        public ChildServicesProxy() : base("ChildService")
        {          
        }
        
        public IList<child> GetChildren(int parentId)
        {
            return Channel.GetChildren(parentId);
        }
    }

Here we see the GetChildren method calls the GetChildren wcf call.

The IChildServices is also implemented on the server

public class ChildServices : IChildServices
    {
        #region IChildServices Members

        public IList<child> GetChildren(int parentId)
        {
//hardcoded but could fetch the children from the database
            if(parentId == 1)
            {
                return new List<child>
                       {
                           new Child
                               {
                                   Name = "Parent 1 - Child 1"
                               },
                           new Child
                               {
                                   Name = "Parent 1 - Child 2"
                               }
                       };    
            }
            if(parentId == 3)
            {
                return new List<child>
                       {
                           new Child
                               {
                                   Name = "Parent 3 - Child 1"
                               }                           
                       };
            }
            return new List<child>();
        }
        #endregion
    }

Here the actual fetching of the data happens. In this case the data is hardcoded but a call to some persistent store could be called here.

The only thing we have to do now is register the implentation of each IChildServices on to the serviceloactor of the client and the server at startup of the applications.

Perhaps more interesting, at least for me, are the pros and cons of using such an approach.
I definitely wouldn't use it by default and it should be very obvious for the consumer he's using a lazy loaded contract as it obviously does imply a major performance hit that one would not immediately link to dereferencing a property.
On the other hand if, at the client side, you map your datacontract on a client-domain I guess it makes more sense to fetch all the data you need at once before mapping it.

Anyway my conclusion is that I would only use this in very specific cases while making more than obvious that the datacontract is a lazy loaded one.

You can find a working version of it here. Please note that it has been stripped down for simplicity reasons.

What are the pros and cons according to you? Would you use this approach and if so in which cases?

Tuesday, 13 December 2011

"is" operator confusion

A while back I stumbled upon the following code.
public void SomeMethod(object param)
        {            
            if(!(param is DateTime?))
            {
                return;
            }
            var d = (DateTime?) param;
            
            if(d.HasValue)
            {
                //do some stuff
            }
        }
Apart from the fact that you shouldn't pas an object to a method when you actualy want it to be a "DateTime?" type (code comes from a wpf converter where the parameter is passed as an object) and that an "as" operator would make a cleaner solution the thing that triggered my interest were the Resharper squigels on the line:

if(d.HasValue) 

It told me "Expression is always true".
How can this always be true? The only thing I know for sure is that the reference has a nullable datetime once I get to that part of the code. But what makes it think it could not be a null value?

As is often the case the answer was simpler than the question... The "is"-operator checks for type but also returns false when the value is null. It doesn't seem logical to me but on the other hand maybe it's a way of forcing you to use the "as"-operator when it comes to reference types.

And indeed when looking at the IL I recieve the following code.

IL_0000: nop
IL_0001: ldarg.0
IL_0002: isinst valuetype [mscorlib]System.Nullable`1
IL_0007: ldnull
IL_0008: cgt.un
IL_000a: stloc.1
IL_000b: ldloc.1
IL_000c: brtrue.s IL_0011
IL_000e: nop
IL_000f: br.s IL_0028
IL_0011: ldarg.0
IL_0012: unbox.any valuetype [mscorlib]System.Nullable`1
IL_0017: stloc.0
IL_0018: ldloca.s d
IL_001a: call instance bool valuetype [mscorlib]System.Nullable`1::get_HasValue()
IL_001f: ldc.i4.0
IL_0020: ceq
IL_0022: stloc.1
IL_0023: ldloc.1
IL_0024: brtrue.s IL_0028
IL_0026: nop
IL_0027: nop
IL_0028: ret


So starting from the top and supposing null is passed as an argument
IL_0001: ldarg.0
the parameter with value null is loaded on the stack
IL_0002: isinst valuetype [mscorlib]System.Nullable`1
the value null is popped from the stack and checked if it is an instance of DateTime? which is not the case so null is pushed on the stack
IL_0007: ldnull
null value is loaded on the stack
IL_0008: cgt.un
the stack is popped twice, in our case meaning null is popped twice from the stack. The null values are compared and as they have the same value 0 is pushed to the stak
IL_000a: stloc.1
pops the value 0 from the stack into variable 1
IL_000b: ldloc.1
pushes the value 0 in variable 1 on to the stack
IL_000c
pops value 0 from the stack and goes to IL_0011 (to continue the program flow) if the value is true which is not the case
IL_000f
goes to IL_0028 and the method is exited

So this brings us back to our C# code and explains why we know for sure that, once we get past the "is"-check,  the param is different from null so HasValue always results in true. Nice job Resharper.

A genuine case of RTFM I suppose. Where in this case M stands for MSDN..

Sunday, 24 April 2011

First blog post.

This is my first blog post. Seems like a lot of people I admire are blogging and promoting it so I might aswell maximize the value of my keystrokes.

The challenge will be to post on a regular basis. I hope I'll keep it up.