Try-Catch-FAIL

Failure is inevitable.

A simple WCF host application

clock October 27, 2009 06:59 by author Matt

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.

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


A fixed ClientBase class for WCF proxies

clock September 27, 2009 09:34 by author Matt

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++;

Share or Bookmark this post…
  • del.icio.us
  • DotNetKicks
  • Digg
  • msdn Social
  • Reddit
  • StumbleUpon

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


About Matt

I am an overworked (and apparently overpaid) software developer with aspirations of acquiring a PhD in Computer Science. I started off coding in C over a decade ago.  Since then, I've migrated from C to C++ and branched out to C#, PHP, VB.NET, JavaScript, and worked with a wide assortment of other languages that I hope to never deal with again (I'm looking at you, COBOL). Oh, and yes, I've written some Java.  Does that make me a bad person?

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in  anyway.

© Copyright 2009

Sign in