making a WCF REST stand-alone service exe from scratch – part 4 of 4, separating out the client and interface

From the previous work, we have a WCF REST service in a console app and we have a client, but one could argue it’s not ‘real’ yet because, well, they’re both in the same console app.

To alleviate that concern, we’ll go ahead and make it ‘real’ by doing the following:

  • moving the client out to a separate console app
  • creating a shared class lib for the interface to live in
    • NOTE: the client could just refer to the existing service project fine, but that’s still kind of cheating, so we’ll not do that
  • moving the client configuration over to the new client app
  • configuring the solution to start both apps

So, let’s add the client exe first:

image

image

Much like the service console exe, we’ll want to change it from the client profile to the full framework. 

image

While you might think the client profile would be enough for a WCF client, there’s a bit of a ‘viral’ thing going on that requires the full framework even for our client:

  • The client profile includes assembly System.ServiceModel, but does NOT include System.ServiceModel.Web
  • Our interface includes use of the WebGet attribute, and that’s in System.ServiceModel.Web
  • Because we’re using that interface, whatever project holds the interface (whether a separate ‘shared’ library or not) will need to use the full framework so it can use that attribute
  • The client project which uses the interface will therefore also need the full framework, since the client profile framework can clearly not load assemblies that depend on the full framework

Being a console exe, the client console exe defaults targeting x86 (32-bit) and while we could change it, we don’t really have a need to do so any more, so I’ll leave it as 32-bit:

image

Now we’ll go ahead and create the ‘shared’ project (also with the full framework, see above) to stick the interface in as well and move the interface to that project (and namespace, to make it more ‘real’ 🙂

image

Since the interface moved (project and namespace), we broke our service project, but we just need to add a project reference and ‘using’, but ReSharper is nice enough to do both for us:

image

While we’re moving code around, we’ll go ahead and move the client code (the stuff inside the ‘using’ of the channel factory) to the client console exe.

class Program
{
    static void Main(string[] args)
    {
        using (var channelFactory = new ChannelFactory<IMyService>(""))
        {
            var channel = channelFactory.CreateChannel();
            var response = channel.AnswerBack("blah");
            Console.WriteLine("Got response of {0}", response);
        }
    }
}

What’s left in our service exe?  We just need to make sure we have something that blocks (Console.ReadLine is fine) to keep our service host open:

class Program
{
    static void Main(string[] args)
    {
        using (var serviceHost = new ServiceHost(typeof(MyService)))
        {
            serviceHost.Open();
            Console.WriteLine("Hit Enter when done");
            Console.ReadLine();
        }
    }
}

Back in the client exe, I let ReSharper add a couple of references and ‘using’ statements here, too (obviously you could do these manually too)

image

image

At this point everything should be building.

image

However, as you might expect, just hitting F5 doesn’t really do anything – when we changed the fully-qualfiied name for the service contract, VS / R# didn’t update the service exe config, so even just running the service exe fails:

image

Since we know that we changed the fully-qualified name so the namespace is now ‘SharedLib’ instead, we’ll just manually edit the app.config to make that change.  Since we haven’t moved the client config over to the new client console exe yet, we need to fix it in 2 places in this app.config, the service and the client:

  <system.serviceModel>
    <client>
      <endpoint 
        name="ourWcfRestClientEndpoint"
        address="http://localhost/testing" 
        contract="SharedLib.IMyService" 
        kind="webHttpEndpoint" />
    </client>
    <services>
      <service name="SimpleWcfRestServiceConsoleApp.MyService">
        <endpoint
          address="http://localhost/testing"
          contract="SharedLib.IMyService"
          kind="webHttpEndpoint" />
      </service>
    </services>
  </system.serviceModel>

Once we fix that, the service will run just fine and we can call it from the browser:

image

image

But wait, we have this great client console app – let’s have it run too 🙂

If we just want a one-time run (the service exe is still running), we can just run it via the Debug context submenu:

image

image

However, more typically we’d want both the client and server to run when we hit F5, so we’ll go into the solution properties and tell it to start both of them:

image

But what happens if we hit F5 now?  Well, we’re not giving the service any time to get going, so the client will do the request before the service is actually listening, causing us to get an endpoint exception:

image

The simplest fix is to just add a sleep in the client to give the service a few seconds to start up before we do the call 🙂

image

With that in place, we can now hit F5 and get what we expected – the server runs, then the client makes its request:

image

There you have it – a simple, from-scratch WCF REST service, hosted in a console app.  Have fun!

Advertisements