ROT 128 Stream Upgrade Sample, Part 2
Building a stream upgrade for ROT 128 starts with creating a binding element to put in the channel stack. This binding element extends the special StreamUpgradeBindingElement base class, which functions very similarly to the specialized binding element base classes for transports and message encoders. We then need to override the channel factory and listener build processes because the stream upgrade binding element does not actually generate a channel. Stream upgrades are handled internally by the transport if it supports them.
using System;
using System.ServiceModel.Channels;
namespace Microsoft.ServiceModel.Samples
{
public class ROT128StreamUpgradeBindingElement : StreamUpgradeBindingElement
{
internal static string ROT128UpgradeType = "application/rot128";
public ROT128StreamUpgradeBindingElement()
: base()
{
}
protected ROT128StreamUpgradeBindingElement(ROT128StreamUpgradeBindingElement copyFrom)
: base(copyFrom)
{
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.BuildInnerChannelFactory<TChannel>();
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.BuildInnerChannelListener<TChannel>();
}
public override StreamUpgradeProvider BuildClientStreamUpgradeProvider(BindingContext context)
{
return new ROT128StreamUpgradeProvider(this, context);
}
public override StreamUpgradeProvider BuildServerStreamUpgradeProvider(BindingContext context)
{
return new ROT128StreamUpgradeProvider(this, context);
}
public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelFactory<TChannel>();
}
public override bool CanBuildChannelListener<TChannel>(BindingContext context)
{
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelListener<TChannel>();
}
public override BindingElement Clone()
{
return new ROT128StreamUpgradeBindingElement(this);
}
public override T GetProperty<T>(BindingContext context)
{
return context.GetInnerProperty<T>();
}
}
}
The only other important task when writing a stream upgrade binding element is to build your stream upgrade provider when asked by the transport. ROT 128 works the same on both the client and server so I've made those methods do exactly the same thing. The stream upgrade provider for this sample isn't going to care which end of the connection it is running on. Stream upgrade construction uses a pull model. Stream upgrade providers aren't required to build anything until specifically asked to generate either the acceptor or initiator. Your stream upgrade just needs to wait for the appropriate method calls to be made.
Next time: ROT 128 Stream Upgrade Sample, Part 3