The final pieces needed for the ROT 128 sample are a stream upgrade initiator and a stream upgrade acceptor. The initiator starts the upgrade process by providing an upgrade type string from GetNextUpgrade. I've coded this so that the initiator and acceptor share a type string that is stored as a static member back on the binding element . You can produce or store your upgrade type string however you want. This is an opaque string to the runtime. using System; using System.IO; using System.ServiceModel; using System.ServiceModel.Channels; namespace Microsoft.ServiceModel.Samples { class InitiateAsyncResult : TypedCompletedAsyncResult<Stream> { internal InitiateAsyncResult(Stream stream, AsyncCallback callback, object state) : base (stream, callback, state) { } } class ROT128StreamUpgradeInitiator : StreamUpgradeInitiator { ROT128StreamUpgradeProvider provider; string nextUpgrade = ROT128StreamUpgradeBindingElement.ROT128UpgradeType; internal ROT128StreamUpgradeInitiator(ROT128StreamUpgradeProvider provider, EndpointAddress remoteAddress, Uri via) : base () { this .provider = provider; } public override IAsyncResult BeginInitiateUpgrade(Stream stream, AsyncCallback callback, object state) { return new InitiateAsyncResult( new ROT128Stream(stream), callback, state); } public override Stream EndInitiateUpgrade(IAsyncResult result) { return ((InitiateAsyncResult)result).Data; } public override string GetNextUpgrade() { string result = nextUpgrade; nextUpgrade = null ; return result; } public override Stream InitiateUpgrade(Stream stream) { return new ROT128Stream(stream); } } } Each time that GetNextUpgrade is called, you're expected to provide a different upgrade type string if you support multiple upgrades. Once you're out of upgrade types to suggest, GetNextUpgrade should return null forever afterwards. This sample only supports a single upgrade type. At some point in the future, after the upgrade is accepted, you'll get a call on InitiateUpgrade to actually perform the Stream transformation. There's no type string given to InitiateUpgrade so, implicitly, calling InitiateUpgrade means to perform the upgrade for the last upgrade type that you passed out of GetNextUpgrade. To get to the point where you're transforming Streams, you first need to make it through the upgrade acceptor. The upgrade acceptor takes an upgrade type string argument to the CanUpgrade method and returns whether it recognizes this upgrade type. If CanUpgrade returns false, then the
Read More...