We've passed the midway point for the custom file transport example. Now that we've got the underlying file code, today's article starts building out the rest of the client-side code. Here's the story so far:

  1. Building a Custom File Transport, Part 1: Planning
  2. Building a Custom File Transport, Part 2: Server
  3. Building a Custom File Transport, Part 3: Client
  4. Building a Custom File Transport, Part 4: Binding and Binding Element
  5. Building a Custom File Transport, Part 5: Channel Basics

The next piece of the puzzle is the channel factory. The factory is rather simple because all it needs to do is configure and build out channels for us on demand. This factory implementation will take the binding element that describes the file transport, combine that with the binding element that describes the message encoding, and build an instance of the transport with all of the configured options. Once the factory is constructed from the binding, there's no sharing of configuration information. This allows you to construct many factories from a single binding, and in the future we'll be constructing many channels from a single factory.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace FileTransport
{
class FileRequestChannelFactory : ChannelFactoryBase<IRequestChannel>
{
readonly BufferManager bufferManager;
readonly MessageEncoderFactory encoderFactory;
public readonly long MaxReceivedMessageSize;
readonly string scheme;
public readonly bool Streamed;

public FileRequestChannelFactory(FileTransportBindingElement transportElement, BindingContext context)
: base(context.Binding)
{
MessageEncodingBindingElement messageEncodingElement = context.UnhandledBindingElements.Remove<MessageEncodingBindingElement>();
this.bufferManager = BufferManager.CreateBufferManager(transportElement.MaxBufferPoolSize, int.MaxValue);
this.encoderFactory = messageEncodingElement.CreateMessageEncoderFactory();
MaxReceivedMessageSize = transportElement.MaxReceivedMessageSize;
this.scheme = transportElement.Scheme;
Streamed = transportElement.Streamed;
}

protected override IRequestChannel OnCreateChannel(EndpointAddress address, Uri via)
{
return new FileRequestChannel(this.bufferManager, this.encoderFactory, address, this, via);
}

public override MessageVersion MessageVersion
{
get { return MessageVersion.Default; }
}

public override string Scheme
{
get { return this.scheme; }
}
}
}

Next time: Building a Custom File Transport, Part 7: Request Channel