Multiple Service Contracts

Mar 21, 2008 at 4:03 PM
Is it best practice to only have a single service contract per project with the WSSF or is it normal to have several service contracts in a project?
Mar 21, 2008 at 11:03 PM
We are developing quite a large enterprise application using WSSF, and we are splitting this this out into about 10 seperate services; each service having it's own service contract diagram. This breaks it down nicely for development purposes and I feel it may be useful in the future as the services could be easily be deployed across multiple servers. And also stops the service contract diagrams becoming too crowded and unwieldy. It works quite nicely.

The one drawback we have is that we can only really have 1 data contract diagram for the whole set of services, as a lot of the data contracts are shared across services, and there is currently no way of splitting these out. We only have 1 service at the moment that has it's own distinct set of data contracts, so in this instance it gets it's own diagram. But the main data contract diagram for the system is getting pretty big now.

Mar 26, 2008 at 3:06 PM
Spencer, you say splitting your service into 10 seperate services and that you in the future can deploy these services on multiple servers. Thats sound nice and I'm about splitting our service into multiple service endpoints too because our WSDL is very big and the autogenerated proxy is about 17000 lines of code!! Will this hit performance?

Even if this code (Service Contracts and Service Implementations) is auto generated from UML models and there is no need for a human to maintain it by hand, I like the idea to split up a VERY HUGE endpoint to multiple endpoints. Is there a known limit on the size for a service contract before performance drop? If it is, then a split is of great value. If not we may just go the way we are going right now.

Mar 26, 2008 at 7:27 PM
One side effect of splitting over several service contracts is that if ServiceA uses the "Customer" data contract, and ServiceB also uses the "Customer" data contract, when you add references to these 2 services in the client it will actually generate 2 "Customer" classes; one under each namespace.

The solution to this (which may or may not be something you are able to do) is to reference the Data, Fault, Message and Service contract assemblies (as used by the services) in the Client app, and write your own simple proxies using the ClientBase<T> class in WCF. I can go into more detail on this is you like. Personally, I'm happier with this method than relying on the huge proxies that VS generates for you, and I get finer control over the proxies too. My proxies are now just a few lines each as all the bulky stuff is already compiled in the assemblies.

Apr 4, 2008 at 11:56 AM
I own both client and service so I able to share the DLL. But I dont like the idea to share a DLL like this, it's not very service-oriented but that is a principle I can swallow. Its not important in my case.

In addition to get smaller endpoints I'm also looking at how to handle unhandled exceptions and timeouts. Is that supported better when using ChannelFactory than using proxy? I guess you are using ChannelFactory when you're shareing DLL? My biggest problem right now is that I cant keep my sessions and connection to the service alive long enough. My service is now and then becomming in a faulted state which makes my system more or less useless.

I would more than gladly listen to your thoughts on both issues and hope you have time to share your thoughts here.
Apr 4, 2008 at 1:45 PM
When I started going down this route, I too was concerned that it was moving away from being true soa. But the fact is I still expose Http endpoints for any third parties to use, and at the same time give my client application (my primary concern) the best flexibility and performance.

One thing using the ChannelFactory enables you to do is provide more control over the service going into a faulted state, and recovering from it. I tried a couple of methods of my own before setttling on a Wrapper class that was provided in a link posted on here a few weeks back. (I can't find the link now though...)

The below is how I have currently got it working. Since doing this I've not had a single error where the service was faulted, so it must be doing something right, although if anyone spots I'm doing something silly please shout.

Firstly, this is the wrapper class that I mentioned above:

    public class ServiceProxyWrapper<TProxy, TChannel> : IDisposable
        where TProxy : ClientBase<TChannel>, new()
        where TChannel : class
    {
        /// <summary>
        /// Private instance of the WCF service proxy.
        /// </summary>
        private TProxy proxy;
 
        /// <summary>
        /// Constructs an instance.
        /// </summary>
        protected ServiceProxyWrapper()
        {
            proxy = new TProxy();
            proxy.Open();
        }
 
        /// <summary>
        /// Gets the WCF service proxy wrapped by this instance.
        /// </summary>
        protected TProxy Proxy
        {
            get
            {
                if (proxy != null)
                {
                    return proxy;
                }
                else
                {
                    throw new ObjectDisposedException("ServiceProxyWrapper");
                }
            }
        }
 
        /// <summary>
        /// Disposes of this instance.
        /// </summary>
        public void Dispose()
        {
            try
            {
                if (proxy != null)
                {
                    if (proxy.State != CommunicationState.Faulted)
                    {
                        proxy.Close();
                    }
                    else
                    {
                        proxy.Abort();
                    }
                }
            }
            catch (CommunicationException)
            {
                proxy.Abort();
            }
            catch (TimeoutException)
            {
                proxy.Abort();
            }
            catch (Exception)
            {
                proxy.Abort();
                throw;
            }
            finally
            {
                proxy = null;
            }
        }
     }

To use this, I firstly write a proxy class around the my service (for simplicty I'm only showing one operation on the service):

    public class PartyServiceProxy : ClientBase<IPartiesService>
    {
        public PartyServiceProxy() : base("Parties") { }
 
        /// <summary>
        /// Get all clients
        /// </summary>
        /// <returns></returns>
        public ClientCollection GetClients()
        {
            try
            {
                GetClientsRequest req = new GetClientsRequest();
 
                GetClientsResponse resp = base.Channel.GetClients(req);
 
                return resp.Clients;
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandleException(ex);
                throw;
            }
        }
    }

And then I create a class that derives from ServiceProxyWrapper and wraps this proxy up so that it disposes of itself properly every time.

   public class PartyService : ServiceProxyWrapper<PartyServiceProxy, IPartiesService>
    {
        /// <summary>
        /// Gets all clients from the system
        /// </summary>
        /// <returns></returns>
        public ClientCollection GetClients()
        {
            return base.Proxy.GetClients();
        }
   }

And finally to use that service I can now just use:

using (PartyService proxy = new PartyService())
{
       clients = proxy.GetClients();
}

You might notice in the proxy code, I catch exceptions and pass them to an ExceptionHandler class. At the moment this is just logging them using the Enterprise Library logging block, and then re-throws them back. I'm not 100% sure of this part still.

One website I've found that has a lot of good information on this is http://blogs.msdn.com/wenlong/default.aspx
Apr 4, 2008 at 3:22 PM
Thank you very much Spencer. Great post. But what about sessions with this approach? Is this taken into consideration here?

In my service I have a connection to a COM server that I need to hold on to. I have a state per-session service and my client is a Web Client, an ASP.NET application and I'm running over HTTP using SOAP.

I'm considering TCP-transport but that is not my priority right now. But if TCP is needed to keep my connection alive throughout sessions I'll go for it immediately . My only goal is to have a bullet-proof solution that let the user be inactive for almost as long as they want. ASP.NET recycling etc. is something you don't control and have to live with :-) I hope you have some comments regarding this issue as well, Spencer?

I'll take a look at your link this weekend and start working on this on monday. But I'll be looking for a post from you even in the weekend hehe. Have a nice weekend!

Apr 19, 2008 at 9:17 AM
Sorry for the dealy, I've only just got the email informing me of a new post in this topic!

I haven't used WCF sessions before so I can't say for certain that this will work with sessions.
From what I've just read up on them, they seem pretty transparent once you've defined them in your service contracts and config files, so I think you should be fine as the above code isn't a million miles away from what the svcutil.exe generated code does, it's just making sure it keeps itself tidy.

Are you having to do anything special at the moment beyond just creating the proxy object and then using it?
Jun 3, 2008 at 11:36 AM
Edited Jun 20, 2008 at 2:56 PM
It is something I dont understand: Why do you dispose the proxy for each call by using the using-statement?
I want to keep the proxy alive because it holds a reference to a COM-server object that needs to be kept alive through the hole http-session.
It is the proxy that holds state for the WCF-service, isn't it? It is the channels you could recreate when in faulted state. The proxy itself should live as long as the user is logged in on the COM-server....... Could you explain this for me?