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     []

7     type MyContract =

8            new() = {}

9            []

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:

[]

type IMyContract =

[]

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.