I ran across another post of someone looking to get rid of WCF on StackOverflow today. The post titled “WCF replacement for cross process/machine communication” goes into the typical complaints about configuration of WCF. I actually think this is the least of the issues I’ve had with WCF. Whatever your reason for looking to abandon WCF, this post is for you. A step-by-step walk-through to get up and running with protobuffers over Win32 rpc.

Step 1 – Gathering dependencies

For this post I’m going to be using VStudio 2008. The primary reason is to show the explicit use of NuGet rather than depending on Visual Studio to do it for us. Now let’s get started. Start by creating a new project in Visual Studio, for this I’m going to use a simple command-line application named “SampleProtoRpc”.

After you have created the project, right-click the project and select “New Folder” and type the name “Depends”. Now visit the NuGet project page and download the “NuGet.exe Command Line bootstrapper”. It should be a single file, “NuGet.exe”. Place this file in the newly created “Depends” directory. From a command-prompt, run NuGet.exe to ensure that you are up and running.

Now right-click the project and select the “Properites” from the bottom. In the properties window, click the “Build Events” tab on the left. In the “Pre-build event command line:” text box enter the following text:

"$(ProjectDir)Depends\NuGet.exe" INSTALL Google.ProtocolBuffers.Rpc -OutputDirectory "$(ProjectDir)Depends" -ExcludeVersion -Version 1.11.1016.3

You can update the version to the latest by checking the current version at http://nuget.org/packages/Google.ProtocolBuffers.Rpc. The reason to use a fixed version is to prevent NuGet from constantly checking with the server to see if it has the latest version. By pinning the version number NuGet.exe will make a quick check and continue if it exists.

Click “Build” and view the Output window, it should contain something like the following text:

------ Build started: Project: SampleProtoRpc, Configuration: Debug Any CPU ------
"E:\Projects\Templates\SampleProtoRpc\Depends\NuGet.exe" INSTALL Google.ProtocolBuffers.Rpc -OutputDirectory "E:\Projects\Templates\SampleProtoRpc\Depends" -ExcludeVersion -Version 1.11.1016.3
Attempting to resolve dependency 'CSharpTest.Net.RpcLibrary (≥ 1.11.924.348)'.
Attempting to resolve dependency 'Google.ProtocolBuffers (≥ 2.4.1.473)'.
Successfully installed 'CSharpTest.Net.RpcLibrary 1.11.924.348'.
Successfully installed 'Google.ProtocolBuffers 2.4.1.473'.
Successfully installed 'Google.ProtocolBuffers.Rpc 1.11.1016.3'.
SampleProtoRpc -> E:\Projects\Templates\SampleProtoRpc\bin\Debug\SampleProtoRpc.exe
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========

Lastly we need to add the dependencies to the project. Right-click the “References” folder in the project and select “Add References…”. Click on the “Browse” tab in the resulting “Add Reference” dialog box. For each of the following files navigate to the directory and select the file:

  • Depends\Google.ProtocolBuffers\lib\net20\Google.ProtocolBuffers.dll
  • Depends\CSharpTest.Net.RpcLibrary\lib\net20\CSharpTest.Net.RpcLibrary.dll
  • Depends\Google.ProtocolBuffers.Rpc\lib\net20\Google.ProtocolBuffers.Rpc.dll

Don’t worry about these being ‘net20′ assemblies, it will work fine in 3.5. If you insist upon native 4.0 images, the first two packages contain net40 versions; however, the Google.ProtocolBuffers.Rpc does not at this time. You will need to pull the source and build a 4.0 version for that library.

Step 2 – Defining a Protocol

Now that we have a project containing the correct dependencies we need to add a protocol definition file. This is a very easy format to write in, if you need help see the Google Protocol Buffers Language Guide. For now let’s get started by right-clicking the project, and selecting “Add” -> “New Item…”. Select the “General” tab on the left, and then pick the “Text File” option from the right-hand list. In the “Name” field, enter “Sample.proto” and click the “Add” button.

Once you have created the file, select “File” -> “Save As…” from the menu. Next to the “Save” button click on the drop-down arrow and choose “Save with Encoding”. Answer “Yes” when prompted to overwrite the file. From the “Encoding:” list, choose the option “US-ASCII – Codepage 20127″ near the end of the list and then click “OK”.

Now we can type a protocol buffer definition in this file. For now we are going to use the following:

package Sample;
option optimize_for = SPEED;

message MyRequest {
  required string message = 1;
}

message MyResponse {
}

service MyService {
  rpc Send (MyRequest) returns (MyResponse);
}

And this will be our first service. To generate the source, we are going to add another pre-build event. Right-click the project and select “Properties” again. On the “Build Events” pane add the following line:

"$(ProjectDir)Depends\Google.ProtocolBuffers\tools\ProtoGen.exe" --proto_path="$(ProjectDir)\" -output_directory="$(ProjectDir)\" -cls_compliance=false -service_generator_type=IRPCDISPATCH "$(ProjectDir)Sample.proto"

You should now be able to build the project successfully. Once completed, right-click the project and choose “Add” -> “Existing Item…”, then select the “Sample.cs” that should appear next to the “Sample.proto” file we created. Admittingly this is a crufty integration at best.

If you are not opposed to it, I would recommend using CmdTool.exe with a configuration similar to this example. CmdTool.exe is available in one of these downloads, you just download, run “CmdTool.exe Register” and save the configuration example in the same directory as the project. That’s about it, you now have all the source generated to do the work.

Step 3 – Implementing the Service

Before we can go much further we must implement our service interface. Right-click the project and add a new Class file so we can create our implementation, I just called mine “Implementation”. The interface has already been defined for us, it’s name will be our service’s name prepended with an ‘I’. Here is a first-pass implementation that simply writes the message to the console.

    class Implementation : IMyService
    {
        #region IMyService Members
        public MyResponse Send(MyRequest myRequest)
        {
            using (WindowsIdentity user = WindowsIdentity.GetCurrent())
            {
                Console.WriteLine("{0} says: {1}", user.Name, myRequest.Message);
                return MyResponse.DefaultInstance;
            }
        }
        #endregion
    }

Step 4 – Setting up the Listener

Time to start playing with our server-side listener. For this example we are going to allow lrpc, tcp, or named pipes. The static IID defines the interface we want to talk to. We can host several interfaces from this process, but this example will only use one. You will notice we create the generated server proxy “MyService.ServerStub” by handing it an implementation of the IMyService interface. This server stub can then be used to create the RpcServer instance. Once we add at least one protocol and call StartListening we are ready to receive calls. The setup is trivial, so without further explanation here is our new ‘Program’ class:

    class Program
    {
        static readonly Guid IID = Marshal.GenerateGuidForType(typeof(IMyService));

        static void Main(string[] args)
        {
            switch (args[0].ToLower())
            {
                case "listen":
                    {
                        using (RpcServer.CreateRpc(IID, new MyService.ServerStub(new Implementation()))
                            .AddAuthNegotiate()
                            .AddProtocol("ncacn_ip_tcp", "8080")
                            .AddProtocol("ncacn_np", @"\pipe\MyService")
                            .AddProtocol("ncalrpc", "MyService")
                            .StartListening())
                        {
                            Console.WriteLine("Waiting for connections...");
                            Console.ReadLine();
                        }
                        break;
                    }
            }
        }
    }

Step 4 – Sending a Message

Now that we have a working server we need to write a client. The reason for the Main() method above to switch on arg[0] for ‘listen’ is that we are going to use the same program for a client. The client case statement below adds support for an LRPC client call:

                case "send-lrpc":
                    {
                        using (MyService client = new MyService(
                            RpcClient.ConnectRpc(IID, "ncalrpc", null, "MyService")
                            .Authenticate(RpcAuthenticationType.Self)))
                        {
                            MyResponse response = client.Send(
                                MyRequest.CreateBuilder().SetMessage("Hello via LRPC!").Build());
                        }
                        break;
                    }

Once we have added this switch case to the Main routine we wrote we now run one process with the ‘listen’ argument, and another one with the ‘send-lrpc’ argument. We should see the following output in the server process:

Waiting for connections...
DOMAIN\user says: Hello via LRPC!

You may now create two additional case labels, one for “send-tcp”, and one for “send-np”. The only difference between them will be the parameters to the RpcClient.ConnectRpc() api. For TCP/IP we will use RpcClient.ConnectRpc(IID, “ncacn_ip_tcp”, @”localhost”, “8080″), and for named-pipes we would use RpcClient.ConnectRpc(IID, “ncacn_np”, @”\\localhost”, @”\pipe\MyService”). Go ahead and fill those in or not at your choosing.

Step 5 – Authentication

By default the RPC server will allow any user (even anonymous users) to connect. This may work for your needs, this may not. Usually you will want to impersonate the caller and then verify they have access to some resource or are a member of a specific group, etc. To do this in a generic way so that we do not have to place the impersonation code in each method we are going to implement the Google.ProtocolBuffers.IRpcServerStub interface. So let’s create a new class now called Impersonation and it’s going to look a lot like the following:

    class Impersonation : IRpcServerStub
    {
        private readonly IRpcServerStub _stub;

        public Impersonation(IRpcServerStub stub)
        {
            _stub = stub;
        }

        public IMessageLite CallMethod(string methodName, ICodedInputStream input, ExtensionRegistry registry)
        {
            using(RpcCallContext.Current.Impersonate())
            {
                return _stub.CallMethod(methodName, input, registry);
            }
        }

        public void Dispose()
        {
            _stub.Dispose();
        }
    }

Once that has been added we will update our server’s listen routine as follows:

                case "listen":
                    {
                        using (RpcServer.CreateRpc(IID, new Impersonation(new MyService.ServerStub(new Implementation())))
                            .AddAuthNegotiate()
                            ... etc ...

Now every call into every method of MyService implementation on the server will be impersonating the client user. The Rpc layer will also ensure that they are NOT an anonymous user.

Zipping it all up…

Server Options: There are numerous extensibility points on the server and client. There are a few worth covering here. The following is a brief outline of the most important configuration options.

  • RpcServer.EnableMultiPart() – Allows unlimited message lengths to be received over tcp/np connections. By default Windows limits these to around 1mb. To circumvent this limitation the server and client can be configured to send messages in multiple parts. Both client and server must enable this for this to work, and doing so will enable server-side connection state.
  • RpcServer.ExceptionDetails – An enumeration value that determines how much exception detail to return to the client. The default, FullDetails, returns all information in the exception including the stack trace.
  • RpcServer.ExtensionRegistry – Allows registration of proto-buffer ‘extensions’ on both your service and on the transport messages defined in csharp_rpc_messages.proto. This can be used as a side-channel to flow information from the client to server and back again.
  • RpcCallContext.Current
  • – This class provides context information about the caller, protocol, authentication, etc.

  • RpcSession.EnableSessions()
  • – Enables session state, accessed via RpcCallContext.Session for the current call.

Client Options: The following controls the client options:

  • RpcClient.EnableMultiPart() – Allows unlimited message lengths to be sent over tcp/np connections. By default Windows limits these to around 1mb. To circumvent this limitation the server and client can be configured to send messages in multiple parts. Both client and server must enable this for this to work, and doing so will enable server-side connection state.
  • RpcClient.ExceptionTypeResolution – This enumeration controls the exception type resolution when an exception is returned from a server. The default, OnlyUseLoadedAssemblies, will only resolve types that are defined in assemblies that have already been loaded into the client process.
  • RpcClient.ExtensionRegistry – Just as for the server, this allows proto-buffer ‘extensions’ to be registered and used when receiving response messages.
  • RpcClient.CallContext – Provides access to the call context instance associated with this connection. Used with the extension registry this allows you to customize side-channel communications between the client and server.

Connection Caching
It should be noted that it is acceptable and generally useful to cache the RpcClient connection; however, you should be aware that a connection can be closed. RpcClient connections will not retry a failed call and will not attempt to reconnect to a server once disconnected. Due to this it is advisable that if you are caching client connections you should create an implementation of Google.ProtocolBuffers.IRpcDispatch. Delegate the actual RpcClient.ConnectRpc() call and configuration to this object so that it can reconnect at will. Finally use this object as as the parameter to the MyService() constructor instead of directly using the RpcClient.ConnectRpc() result.

zip Download the Sample RPC Project
The project zip file is completely stand-alone. Just extract the contents and open the solution to build.
 

Recently I ran across an article on the subject of Content Management Systems and their inability to separate content editing from content publishing. The article titled “EditingPublishingSeparation” by Martin Fowler is worth a read.

I completely agree with his assertion that, from an architecture point of view, the editing and publishing of content should be separated. I would however take the assertion much farther than that. Websites should NOT be capable of editing themselves. The mere idea of this is absurd IMHO. I’ve written CMS systems before back in the late 90′s, and even then it was obvious. You can not secure a self-editing website.

Why is a self-editing website a bad idea?

1. The group take down. To say most CMS systems have a vulnerability or two is putting it mildly. Attackers love to take these vulnerabilities and then proceed to use automated software to seek out sites using that CMS and exploit them. This allows them to inexpensively disperse malware to a large audience in a very short period of time. This, IMHO, is the worst thing about running a CMS solution. Nobody specifically targeted your site, it just happened to be running on software they knew how to attack. No provocation needed, you got taken down with 10,000 other unfortunate people.

2. It runs in the browser. The issue here is that some form of logon allows users to modify the content on the web server. This means that the user’s horribly insecure browser environment is entirely in control of ‘production’ content. Thus a simple XSS script, a malicious browser plugin, or other common vulnerability can allow an attacker to modify content. Browsers are the worst place to be editing content. Even with the advent of Windows Live Writer and other rich-client authoring tools you still occasionally need to log into the website. So these tools help, but they do not fix the problem.

3. Preview is not a preview. Most all the of the CMS systems out there will allow you to preview the content before publishing it. Most of them get it wrong. It seems CMS systems are more and more moving to a “wysiwyg” display editing where they modify the output HTML so that you can edit it, even in preview. This then gives you no assurance about how it will actually format and display since the authoring widgets on screen change the HTML being rendered. Furthermore while previewing a single page is possible many CMS systems will not allow you to preview entirely new sections and navigation elements. Lastly previewing an entire redesign of the site’s look-and-feel, navigation structure, etc is also not possible.

4. My web server runs DRY. CMS systems often fail to appropriately cache the rendered HTML. This produces lags in performance as you server must reprocess the same content against the template over and over again. I prefer my sever to run as DRY as possible, Don’t Repeat Yourself. There is just no point in reprocessing the content for every request.

5. User provided content. IMHO, user authored content does not belong on your sever. This is one of the driving factors behind #4 and is simply not necessary. Using Facebook or another discussion server is easy. If you need something more fancy that what is freely available, go build it. Stand up a completely different site on a different domain with a completely different authentication model. Users should never log in to your site.

6. XCopy backup and deployment. Asside from backup and deployment there is also the issue with applying a version control system to most CMS systems. This is one of my biggest pet-peeves with CMS systems. They absolutely love to rely on a database back-end. Although some newer CMS solutions can use embeded sql servers, most do not support it and this is not an option if you are farming the content across several servers. I suspect most CMS sites are not being backed up regularly and if the server is lost or it’s drive corrupted their likely to loose most if not all of their site.

What are my alternatives?

1. Find a better CMS. I’m not aware of a single CMS system in operation today that avoids the issues above. Please correct me in the comments if this is inaccurate, I’d love to know if one exists.

2. Using a CDN (Content Distribution Network). These are often very powerful tools and can be configured to avoid many of the issues mentioned above. If you are looking for one I would consider CloudFlare a viable starting point.

3. HttpClone or similar product. I’m sure there are other solutions that have similar capabilities, but honestly I love using HttpClone. I use WordPress on the back-end and have a deployment script that automates the process end-to-end. Whether I’m publishing the result to a test server or to production it’s relatively easy once you get it working. The hard part was the configuration of the crawler to identify content I wanted removed or changed, and indexing for search. Once that was complete I wrote a simple batch file to do the deployment that looks roughly like:

@ECHO OFF
HttpClone.exe crawlsite http://csharptest.net/index.html
HttpClone.exe copysite http://csharptest.net/index.html http://csharptest.net/index.html /overwrite
HttpClone.exe optimize http://csharptest.net/index.html
HttpClone.exe index http://csharptest.net/index.html
HttpClone.exe addrelated http://csharptest.net/index.html
HttpClone.exe publish http://csharptest.net/index.html
mysqldump.exe -u root -ppassword --create-options --skip-extended-insert --databases csharptest --result-file=csharptest.sql

Basically what this does is crawls my locally running copy of this website (admin.csharptest.net) and captures the results. Then it crawls all the pages and changes references from admin.csharptest.net to csharptest.net overwriting the content that was previously there. Then it performs a series of steps: optimizing the content, creating the search index, and injecting related article links. Finally it packages and publishes all the content to the remote site, and then backs up the database. The entire site is instantly switched to the new content once it is ready. For small edits I can choose to publish the content directly to production, or more often I push to a local site to then verify the content package.

Obviously the most vulnerable part of the process is the code on the server that allows publication. This is why the entire thing requires the client and server to know each-other’s public key. They negotiate a session key, transfer the file, and sign/verify every request and response. This code uses the CSharpTest.Net.Crypto.SecureTransfer class from my library if you are interested in the details.

The benefit to both client and server using a public/private key is that an observer knowing only one of the two keys can learn very little about the content being transferred. It should be obvious that if an attacker obtains the servers private key they can replace the server (assuming some form of DNS poisoning or the like); however, they will not be able to then forward it to the actual server and still be able to read the content. Again it should be obvious that if someone were to obtain my client private key they can publish new or modified content to the server since this is the only form of authentication. I will add that even with my client private key they still can not upload anything that is executable on the server. This leaves my server secure and in-tact and all that is needed for me to recover is replacing the client key and republishing the content.

I wish the guys at WordPress or another CMS would just do this out of the box.