F# does a WCF Service


I spent a large portion of my career working with WS-*/SOAP. So, once I understood how F# attributes worked, I thought it would be cool to see if I could write a WCF service. Nothing complex– I just wanted to see if I could get HelloWorld up and running. Given that one can get a class running as a service with the right config and .svc file, this seemed like an easy task. First, I’ll present the solution, then I’ll talk about a couple of issues I ran into along the way to the solution. In F#, one adds attributes by placing a [<Attribute>] before the type or member. For WCF, we need the ServiceContractAttribute and OperationContractAttribute on the type and any exposed functions. The HelloWorld service can be written like this:

 

    1 #light

    2 

    3 namespace Service

    4     open System.ServiceModel

    5 

    6     [<ServiceContract>]

    7     type MyContract =

    8            new() = {}

    9            [<OperationContract>]

   10            member x.HelloWorld(name: string)= “Hello, “ + name

 

Following the path most folks take, hosting in IIS, we next write a .svc file with the following content:

<%@ ServiceHost Service=”Service.MyContract”  %>

This just tells the ServiceHostFactory to instantiate an object of type Service.MyContract whenever a request comes in. Finally, we go into web.config and add the following markup:

 

    1     <system.serviceModel>

    2         <behaviors>

    3             <serviceBehaviors>

    4                 <behavior name=SimpleService.SimpleServiceBehavior>

    5                     <serviceMetadata httpGetEnabled=true/>

    6                     <serviceDebug includeExceptionDetailInFaults=false/>

    7                 </behavior>

    8             </serviceBehaviors>

    9         </behaviors>

   10         <services>

   11             <service behaviorConfiguration=SimpleService.SimpleServiceBehavior name=Service.MyContract>

   12                 <endpoint address=“” binding=wsHttpBinding contract=Service.MyContract>

   13                     <identity>

   14                         <dns value=localhost/>

   15                     </identity>

   16                 </endpoint>

   17                 <endpoint address=mex binding=mexHttpBinding contract=IMetadataExchange/>

   18             </service>

   19         </services>

   20     </system.serviceModel>

Finally, I wrote a client application in C#, using Add Service Reference in VS2008 to generate the client code.

 

    1 class Program

    2 {

    3     static void Main(string[] args)

    4     {

    5         using (ServiceReference1.MyContractClient client = new SimpleClient.ServiceReference1.MyContractClient())

    6         {

    7             Console.WriteLine(client.HelloWorld(“Scott”));

    8         }

    9     }

   10 }

And it all worked just fine. I know– it’s all .NET and that’s the way things should work. I’m most impressed by the terseness of F#.

OK, so what did I learn while doing this? First off, F# does NOT create a default, empty constructor for classes. WCF barked at me when I tried to access the SVC file, stating that it couldn’t create the object because the object lacked a default constructor. So, I dug into the F# spec and learned that a default, do nothing constructor looks like

 

           new() = {}

I also tried doing this in the traditional way, with an interface definition first and then an implementation of the interface. That didn’t work so well. In F#, the interface looks like this:

 

    [<ServiceContract>]

    type IMyContract =

            [<OperationContract>]

            abstract HelloWorld : string -> string

 

That little bit on HelloWorld states that the input is a single string that yields a string. The input parameter does not have a name, and that’s a problem. No name means no name, null, in F#. When System.ServiceModel does its reflection thing to figure out what the name of the parameter in the message should be, it sees a null and throws up its hands. I was able to name the parameter only when applying the attributes on the named parameter in the implementation. So, I ditched the interface. Maybe I missed something that would allow me to name the parameter, but I’m not too sure what it could be. For now, I’ll assume that this was a legitimate issue. I’ll update this post if I learn otherwise.

%d bloggers like this: