Minimal WCF and REST (or whatever else you might want)

The original versions of WCF were great if you wanted to expose SOAP-RPC endpoints with predefined methods driven off of reflection in your code, but as developers in the .NET space move to join the rest of the world with REST and general HTTP services that aren’t quite so static as SOAP-RPC, where does that leave WCF?

Here is a minimalist version of a standalone WCF service—no XML in app.config or web.config, no IIS, no generated classes—just a copy-pasteable example of getting a minimal arbitrary HTTP server up and running in WCF. Note that this code requires .NET 4.0 because it uses the new ByteStreamMessageEncodingBindingElement class to allow for tighter control over the serialized output.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
 
[ServiceContract]
[ServiceBehavior(
    InstanceContextMode = InstanceContextMode.Single,
    AddressFilterMode = AddressFilterMode.Any)]
public class GenericService
{
    /// <summary>
    /// Starts up a generic HTTP service.
    /// </summary>
    /// <param name="args">
    /// Arguments to the event.
    /// </param>
    public static void Main(string[] args)
    {
        Uri uri = new Uri("http://localhost:9000/");
        var serviceImpl = new GenericService();
        using (var host = new ServiceHost(serviceImpl))
        {
            // this gives you complete control over the stream
            var binding = new CustomBinding(
                new ByteStreamMessageEncodingBindingElement(),
                new HttpTransportBindingElement());
 
            host.AddServiceEndpoint(typeof(GenericService), binding, uri);
 
            // begin listening for connections
            host.Open()
 
            // display a little message and wait for the user
            // to kill the console app
            Console.WriteLine("Listening on URI: {0}", uri);
            Console.WriteLine("Press ENTER to stop the service.");
            Console.ReadLine();
        }
    }
 
    [OperationContract(Action = "*", ReplyAction = "*")]
    public Message Process(Message message)
    {
        // this is the incoming URI; we're not doing anything with it
        // here, but you almost certainly will
        Uri uri = message.Headers.To;
 
        // build a stream of bytes that represents the text "Test" in UTF-8
        var bytes = Encoding.UTF8.GetBytes("Test");
        var memStream = new MemoryStream(bytes);
 
        // create and return the response message
        return Message.CreateMessage(
            MessageVersion.None,
            "OK",
            new BodyStreamProviderWriter(memStream));
    }
}

And the implementation of BodyStreamProviderWriter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System.IO;
using System.ServiceModel.Channels;
using System.Xml;
 
/// <summary>
/// Allows an arbitrary <see cref="Stream"/> to be serialized.
/// Use in conjunction with the overloads of the
/// <see cref="Message"/>.CreateMessage method.
/// </summary>
public sealed class BodyStreamProviderWriter : BodyWriter, IStreamProvider
{
    private readonly Stream innerStream;
 
    public BodyStreamProviderWriter(Stream stream) : base(false)
    {
        this.innerStream = stream;
    }
 
    protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
    {
        writer.WriteStartElement("Binary");
        writer.WriteValue((IStreamProvider)this);
        writer.WriteEndElement();
    }
 
    Stream IStreamProvider.GetStream()
    {
        return this.innerStream;
    }
 
    void IStreamProvider.ReleaseStream(Stream stream)
    {
        if (stream != null)
        {
            stream.Dispose();
        }
    }
}

GenericService.cs
BodyStreamProviderWriter.cs

And presto–you’ve got a miminal WCF service for your RESTful purposes (or whatever else you might want). —DKT