During the last few weeks I've been going over various parts of the channel model and giving some commentary about using those classes. Looking back at the list of topics, we've already covered everything you need to build a custom transport. Today I'm starting a series that ties everything together by going step-by-step through building a custom transport over a file protocol.
Here are the basics of the protocol. We're creating a new scheme called "my.file" that ignores the hostname and port and just uses the path of the URI. The path indicates a directory on the file system that we'll use to exchange messages. The transport will expose a request-reply interface. The request channel writes its message to a file in the directory called "request". The reply channel then reads the message and writes its response message to a file in the same directory called "reply". You can use any encoding you want with this protocol, but there is no default encoding.
To keep the example simple, I've cut a few features out of the transport. You won't want to use this transport in a production system!
- Only synchronous operations are supported. All of the asynchronous methods will throw if you call them. We don't call any methods behind your back at the channel model level, so as long as the client and server don't explicitly call an asynchronous method you'll never hit these code paths.
- There is no additional security checking in the transport. The channel will try to write messages to wherever someone tells it to and the only thing that will stop it is any permission settings you have on your file system.
- All exceptions are treated as fatal. This is a good way to demonstrate that the expected case doesn't throw any exceptions.
- The transport is not optimized for performance. Even though the transport supports both buffered and streamed transfers, there are some inefficient data copies that take place. This transport uses the standard Message class, which is not going to be as optimized as a transport-specific message would be. You also aren't going to get top performance using synchronous operations.
- There is only support for configuration through code. I haven't covered file-based configuration yet. When I write that series, I'll go back and extend this sample as a demonstration.
I'm not going to call out specific past articles most of the time during this series. Almost everything has been talked about at one point in time if you look at the archive. Here's a master list of classes that get extended by the sample. You'll have to follow the links in the articles to get to parent classes and interfaces where applicable.
- ChannelFactoryBase and ChannelListenerBase
There's actually a total of ten classes in the sample. The two classes that don't appear in the above list are the client and server.