The stream upgrade model consists of four abstract base classes. We looked at the StreamUpgradeBindingElement yesterday. Since stream upgrades don't have a corresponding channel, the only purpose of the binding element is to notify the transport that this binding is interested in having a potential stream upgrade available. If the transport does not support stream upgrades, then it will ignore this request and the stream upgrade binding element will go unhandled. It is up to the transport to at some point initialize the stream upgrade.

The other three parts of the stream upgrade model are the StreamUpgradeProvider, StreamUpgradeInitiator, and StreamUpgradeAcceptor. The binding element is responsible for creating the provider. The provider is then responsible for creating the initiator and acceptor as needed. We'll look at the provider today and look at the initiator and acceptor tomorrow.

public abstract class StreamUpgradeProvider : CommunicationObject
{
protected StreamUpgradeProvider();
protected StreamUpgradeProvider(IDefaultCommunicationTimeouts timeouts);

protected override TimeSpan DefaultCloseTimeout { get; }
protected override TimeSpan DefaultOpenTimeout { get; }

public abstract StreamUpgradeAcceptor CreateUpgradeAcceptor();
public abstract StreamUpgradeInitiator CreateUpgradeInitiator(EndpointAddress remoteAddress, Uri via);
}

Although stream upgrades aren't channels, the provider shares the Open, Close, and Abort functionality of ICommunicationObject. In Open, the provider takes care of any work that needs to be completed prior to being able to offer an upgrade. For example, a security stream upgrade might use the call to the Open method to allocate credentials or certificates that the local endpoint will present as its identity. The Close and Abort methods allow the provider to clean up any resources allocated in Open or in the created upgrades.

Take note of the fact that nothing related to the initiator or acceptor has a timeout parameter. The only timeouts on the provider are on the methods that come from ICommunicationObject. This does not mean that you have an unlimited amount of time to complete operations. Stream upgrades are run as part of a larger bounded operation, such as a receive, and you simply don't know how much of that time slice is remaining. This is an unfortunate part of the model, but it also encourages you to frontload as much work as possible into the startup of the provider.

Next time: Stream Upgrades, Part 3