Apr 15 2010

Towards a better Windows Communication Foundation

Category: WCFMatt @ 12:48

Windows Communication Foundation (WCF) is The One Way to implement inter-process communication on the .NET platform.  Well, it’s not really the only way, but it’s certainly the most common way.  It’s a bit misused.  Unfortunately, WCF suffers from numerous problems.  It is extremely configuration heavy, it has known design issues, and it has a learning curve that nearly rivals Lisp.  We need a better way to handle inter-process communication in the .NET world.  I’m not proposing a solution in this post, merely throwing out some ideas.  Feedback is welcome in the comments!

What is Windows Communication Foundation?

From MSDN:

Windows Communication Foundation (WCF) is Microsoft’s unified programming model for building service-oriented applications. It enables developers to build secure, reliable, transacted solutions that integrate across platforms and interoperate with existing investments.

Basically, WCF is a highly-configurable API for communication to/from services.  It’s the successor to both ASMX Web Services and .NET Remoting.  It has several advantages over both technologies, not the least of which is the separation of the “contract” from the implementation.  It’s quite useful for building loosely-coupled, standards-compliant end points. 

What’s wrong with it?

Configurability adds complexity, and WCF is very configurable, making it very complex.  There are tools written around managing the app.config entries that it requires.  You can choose to configure WCF via code, but this is not the recommend approach, and it’s still more complicated than it should be.

WCF also suffers from some pretty serious design issues.  For whatever reason, even as we have reached the second major .NET revision since WCF was introduced, the WCF “dispose” semantics remain broken.

The “proxies” themselves are another problem with WCF.  They look exactly like a normal class.  If you hide them behind an interface reference, the fact that you are dealing with a proxy object can be totally obscured, leading to poor implementation choices downstream.  While this is certainly convenient in terms of cranking out code, the drawbacks can be severe.  Imagine how the following will perform if the IDataSource instance is actually a proxy for a remote object instead of a local object. 

public void ListResults(IDataSource source, int count)
{
    for (int i=0; i < count; i++)
    {
        //This is what we'd call a 'chatty' interface...
        Console.WriteLine(source.GetItem(i));
    }
}

In a nutshell, I’d summarize WCF as a tool that tries to solve every problem but only manages to become too complicated to effectively solve much of anything.  It tries to make a complex problem (inter-process communication) simpler by masking it under layer upon layer of abstraction.  This is exactly the same approach that ASP.NET WebForms took.  Does it work some of the time?  Sure.  But most of the time it causes far more pain than it prevents.

What should be done differently?

I think attempting to create a single, unified API that can solve every problem via reconfiguration is a really bad idea.  With WCF we can configure every single aspect of the end point, the transport, the channel, etc.  There are defaults for many things, but even using the defaults where possible won’t get your configuration much below 20 lines of app.config mess. 

Instead, I would like to see specialized APIs to tackle each type of problem.  (We’re already making a little progress on this front with things like NServiceBus, which provides an API that is tailored to the types of problems service buses are meant to solve.)  Instead of requiring extensive configuration, the APIs should adopt intelligent (but swappable) conventions, allowing users to get up and running with the API with near-zero configuration while still providing plenty of hooks for extensibility.  I think sacrificing some flexibility in order to avoid complexity is a good trade. 

Another problem: right now, I’d say that making synchronous calls is the path-of-least-resistance when using WCF.  Sure, WCF supports asynchronous calls, but I think most developers fall into the easy trap of making synchronous calls. I think the remote APIs should be asynchronous-by-default.  It should take (some) extra work to make synchronous inter-process calls, thereby redirecting developers towards a better design for their distributed systems.  Making synchronous web service calls is a good way to kill your system’s performance.

One common use case I keep bumping in to is making a Remote Procedure Call to a service on another physical machine.  Handling that with WCF requires extensive configuration on both ends.  I’m not sure exactly what I’d like to see on the server-side, but perhaps something like this (inspired by StructureMap):

public class MyServiceObjects : ServiceRegistry
{
    public MyServiceObjects()
    {
        //This would load default conventions for things like 
        //channel and endpoint settings, but it could be replaced
        //by your own conventions. 
        With.DefaultConventions();
        
        //By default, expose services over a TCP channel
        Expose<IDataSource>().Using<ConcreteDataSource>();
        
        //Changing to an alternate channel should still be trivial. 
        Expose<ICommandableThing>().OverHttps().Using<ConcreteCommandableThing>();
    }
}

Note that there are no app.config settings needed for this.  All the configuration data would come from the conventions (defined in code) or would be explicitly specified in the registry.  Are there downsides to this?  Sure: I can’t decide to change how my services are exposed without recompiling my application.  I don’t see that as being a big loss.

Client-side, I think it should be very clear when you are using a remote object.  The remote object should not pass for a local one (at least not without having to jump through a small hoop; after all, there are going to be times when treating it as a local object makes perfect sense).  The proxy should be asynchronous by default and support batching remote calls.  Here’s what my previous example might look like with such an API:

public void ListResults(string remoteSourceUrl, int count)
{
    var proxy = RemoteProxy.For<IDataSource>(remoteSourceUrl);

    using (proxy.BeginBatch())
    {
        for (int i=0; i < count; i++)
        {
            //The first lambda is the call on the data source.
            //The second lambda is the callback to run when the 
            //remote call completes. 
            proxy.Call(ds => ds.GetItem(i), item => Console.WriteLine(item));
        }
    }
}

So what do we do?

I’m not sure.  Microsoft has shown no real hint of backing off from WCF despite the overwhelming negative feelings that most of the .NET community has about it, but I don’t see a lot of effort by the community to develop alternatives aside from the various service buses.  Maybe I’m overlooking something (if so, let me know).  I’d love to work on something like this, but my workload is already overwhelming me.  If there’s an effort by someone out there to implement something along these lines though, I’d be game for helping out when/where I can.

Tags:

Oct 27 2009

A simple WCF host application

Category: WCFMatt @ 06:59

I’ve been struggling with getting some of our backend components to play nice over WCF for the past couple of days.  Our situation is a little more complex than most I think; our systems have dependencies on a variety of COM libraries, uses some Java APIs via IKVM.NET, and has differing capabilities as far as 64-bit goes. 

What didn’t work

So I tried many things over the course of the last week.  The following is basically a brain dump of every issue I ran in to as well as solutions if I ever found one:

IIS Hosting

The services we were trying to host were to be exposed over the NetTcpBinding, which works fine with IIS7+.  I was able to get stripped-down “Hello, World!” prototype working quite quickly.  What didn’t work was hosting our service in IIS7.  As it turns out, there are apparently some major issues with using IKVM.NET in an ASP.NET environment, which is apparently how even NetTcpBinding services are hosted in IIS.  Bummer.  I never found a solution to this problem.

Sending large objects

Some of the objects we were transmitting over the wire were up to 10MB in size.  Out of the box, WCF will explode with helpful messages about buffer sizes and such.  This was easy to fix through configuration, just be sure you put the config on the right end of the channel (the server-side):

<system.serviceModel>
<services>
  <service ... >
    <endpoint binding="netTcpBinding" bindingConfiguration="MyCustomBinding" ...>
    </endpoint>
    ...
  </service>
</services>
...
<bindings>
  <netTcpBinding>
    <binding name="MyCustomBinding" ... maxBufferSize="20971520" maxReceivedMessageSize="20971520" >
      <readerQuotas maxArrayLength="10485760" maxStringContentLength="10485760" />
    </binding>
  </netTcpBinding>
</bindings>
</system.serviceModel>

Sending too many objects too quickly

We ran into some timeout issues when many threads tried to hammer the service with large amounts of data in parallel.  By default, WCF communications will time out after 1:00.  While that should be enough most of the time, it isn’t always the case.  Fortunately again, it’s a pretty easy fix, just increase the timeout values.  The timeout can be configured on the proxy client-side and on the server-side.  You will probably need to change it on both sides (I did). 

IDisposawhat?

It’s well-known that WCF proxies are in fact broken.  See my previous article about how we created a better base class for our proxies. 

Port Sharing

If the service you are trying to expose over WCF implements multiple contracts, you will need to expose multiple endpoints.  You probably don’t want to have each contract on a separate port, but by default, that’s what you will have to do, because you can’t have two listeners on the same port.  Net.Tcp Port Sharing Service to the rescue!  This Windows Service, installed along with the .NET Framework, enables your WCF NetTcpBinding endpoints share ports.  After making sure the service is enabled (it is disabled by default), you can take advantage of it by setting the portSharingEnabled attribute to true on the binding configuration, like so:

<system.serviceModel>
    <services>
        <service ...>
            <endpoint binding="netTcpBinding" bindingConfiguration="MyCustomBinding" ...>
            </endpoint>
            ...
        </service>
    </services>
    ...
    <bindings>
        <netTcpBinding>
            <binding name="MyCustomBinding" portSharingEnabled="true" ...>
                ...
            </binding>
        </netTcpBinding>
    </bindings>
</system.serviceModel>

The Final Host

As I said, our services were not compatible with IIS hosting due to various COM issues as well as IKVM.NET dependencies.  That left us with two options: self-host the services in a custom application, or create Windows Services to serve as hosts.  We decided to go the self-host route so that deploying our services would remain dirt-simple (it doesn’t get much simpler than XCOPY).  Below is a skeleton class that you can use to host a WCF service in a console application.  Pressing Ctrl+C will shut the service down gracefully and exit:

class Program
{
    //Log4net logger
    private static readonly ILog mLogger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    private static readonly AutoResetEvent mStopFlag = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        //When the user hits Ctrl+C, the server will be shut down. 
        Console.CancelKeyPress += delegate
                                    {
                                        mLogger.Info("Shutting down server thread.");
                                        mStopFlag.Set();
                                    };

        var serverThread = new Thread(ServerThread) {IsBackground = true};
        serverThread.Start();

        serverThread.Join();
    }

    private static void ServerThread()
    {
        //This will grab the WCF configuration from the app.config file.
        using (ServiceHost host = new ServiceHost(new MyService()))
        {
            host.Open();

            mLogger.Debug("Service is online and awaiting requests...");

            Console.WriteLine("running");
            mStopFlag.WaitOne();
        }

        Console.WriteLine("stopped");
    }
}

Suggestions

I confess to being a total WCF newb, so it’s quite likely that I’ve done something wrong.  If you see any incorrect information or have suggestions for things we could do better, please let me know. :)

**UPDATE – 10/29/09**

There is actually a bug in the host application I presented.  While it will allow the background thread to shut down gracefully, it will still cause the application to abort abnormally, which means any pending finalizers and things won’t be executed.  To resolve the issue, use the following CancelKeyPress handler instead:

Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs cancelEventArgs)
                            {
                                mLogger.Info("Shutting down server thread.");
                                mStopFlag.Set();
                                //This is IMPORTANT.
                                cancelEventArgs.Cancel = true;
                            };

Thanks go to James for pointing this out.

Tags:

Sep 27 2009

A fixed ClientBase class for WCF proxies

Category: WCFMatt @ 09:34

It’s a well-known point of pain for Windows Communication Foundation developers that ClientBase<T> is, in fact, broken.  Though it implements IDisposable, calling Dispose doesn’t clean everything up in all cases.  Instead, you have to close the channel manually (aborting it instead if it is faulted), handle errors, then dispose of it.  I’m not sure why this approach was chosen, but given how obvious the problem is and how much pain it’s caused, I have to think there’s a very good reason it is the way it is.

I set about this weekend to try and fix this problem for the proxies we use at InRAD.  Our proxies all derive from ClientBase<T>, so I thought “Hey, I’ll just make a new base class for our proxies by inheriting from ClientBase<T>!”  For this to work, I knew I’d want my custom base class to implement a new IDisposable.Dispose method which would close/abort the channel, then call ClientBase’s Dispose method.  This turned out to be a lot more complicated than it sounds.

The first part was very easy.  I setup my disposable method like so:

void IDisposable.Dispose()
{
    if (State == CommunicationState.Faulted)
    {
        Abort();
    }
    else
    {
        try
        {
            Close();
        }
        catch
        {
            Abort();
        }
    }
    
    //TODO: Call the base-class Dispose method.
}

If the channel is faulted, it calls Abort, otherwise it tries to call Close, and if that fails, it falls-back and calls Abort again.  Fairly straight-forward, all that remains is to call the base Dispose method.  There’s just one problem.  It is explicitly implemented.   That means you can’t get to it without casting to IDisposable.  And you can’t do ((IDisposable)base).Dispose() as base can’t be used in that way.  You also can’t do ((IDisposable)(ClientBase<T>)this).Dipose(), as that refers to the current Dispose method and not the base class implementation.  Ruh-roh. 

After lots of Googling and lots of “No, you can’t do that” answers, I found a post by Eyal Safran that showed me how to do what I wanted, just not in the way I wanted.  The solution is to use reflection:

void IDisposable.Dispose()
{
    if (State == CommunicationState.Faulted)
    {
        Abort();
    }
    else
    {
        try
        {
            Close();
        }
        catch
        {
            Abort();
        }
    }

    //Call the base-class implementation of IDisposable.Dispose. 
    typeof (ClientBase<TChannel>).GetInterfaceMap(typeof (IDisposable)).TargetMethods[0].Invoke(this, null);
}

So, problem solved, right?  Well, no, not really.  At this point, I thought “Hey, I wonder what that base Dispose method is actually doing?”, so I fired up Reflector (shame on you, redgate, for requiring registration in order to download such an awesome and formerly-no-strings-attached tool).

It turns out that you don’t even need to call the base class Dispose implementation in this case.  All ClientBase.Dispose is going to do is call Close, which the new Dispose method is going to do anyway, so you can actually omit the reflection and just not call the base Dispose implementation for now.  Who knows if that will be true in future versions of WCF and the framework. 

In any case, the custom proxy base class allows me to combine my proxies with the using statement and get the semantics that I expect, and I now know how to call an explicitly implemented interface from a derived class that also implements the same interface.  Knowledge++;

Tags: