The HTTP transport and binding element have three settings for controlling the proxy behavior.
public bool BypassProxyOnLocal { get; set; }public Uri ProxyAddress { get; set; }public bool UseDefaultWebProxy { get; set; }
UseDefaultWebProxy controls whether manual proxy settings are used or whether the automatically-configured system proxy settings are used. ProxyAddress is how you manually specify the proxy. If you're using the automatically-configured proxy, then you can't also specify a manual proxy address. Finally, BypassProxyOnLocal allows you to control whether the proxy is used for destination addresses that are on your local network.
Requests to any loopback adapter address or the special host name localhost are always bypassed. Even if you set BypassProxyOnLocal to false, requests to these addresses will still not go through the proxy. Unfortunately, overriding this behavior would require writing a custom instance of IWebProxy and attaching that proxy to the underlying web requests that are being made. It's more common to hit this problem during development when you're testing on a machine that doesn't have the same networking setup that the real server will have. One workaround is to install a virtual network adapter that performs loopback in software. This allows you to send requests to an address that is not classified as a loopback without having to add new hardware to your system.
Next time: Registration of Base Addesses
IIS uses some inscrutable strings to configure the activatable bindings of a web site. Here's the minimum you need to interpret a binding and get started working with activation. Activation is controlled by the activationHost.config file. In the list of web sites, each site has a binding section that contains the list of supported protocols.
<site name="Default Web Site" id="1"> <bindings> <binding protocol="HTTP" bindingInformation="*:80:" /> <binding protocol="net.tcp" bindingInformation="808:*" /> </bindings></site>
The format for the HTTP binding information comes from IIS. It has three parts separated by colons. The three parts are
The format for TCP was picked to be as similar as possible to what already existed for HTTP. We have two parts to configure, again separated by colons. There is no equivalent for the list of addresses. The two parts are
Next time: Proxy Bypassing Behavior
The synchronization context is invisible state that flows around making sure that the proper threading model is being used with requests. Windows Forms applications, for example, require that calls be made on a particular thread and the synchronization context makes sure that that thread marshalling takes place. Rarely though, you need to manually intervene in this process. Access to your synchronization context is provided through static variables. Here is some code showing how to make a call while bypassing the synchronization context that is current in place.
SynchronizationContext oldContext = SynchronizationContext.Current;try{ SynchronizationContext.SetSynchronizationContext(null); proxy.Open();}finally{ SynchronizationContext.SetSynchronizationContext(oldContext);}
There's a tricky example of manually controlling the synchronization context. By default, we want service calls to work correctly when made from a Windows Forms application. The synchronization context is used while opening up a proxy to make sure that everything happens on the right thread. On the other hand, IIS hosted applications are not compatible with that thread model, so when we're running in a hosted environment we don't use the synchronization context. This normally isn't a problem because you don't have a user interface running on the server.
If you make a call out from your hosted service using a composite duplex binding, then you're opening up a new service host inside of your service host inside of IIS. This nested service host doesn't realize that it too is web hosted and tries to use the forbidden synchronization context. IIS will eventually bomb because of this thread misuse unless you use something like the code snippet above. There are other reasons why you shouldn't open up new service hosts inside of a web-hosted service, but it makes a good example.
Next time: Format for Configuring HTTP and TCP Activation
What's wrong with the following code? The error message when you try this is better than it used to be a few months ago. However, since you don't see the error until you try to run your service, I still see people making this mistake.
[MessageContract]public class MyMessage{ [MessageBodyMember] public string name;}[ServiceContract]public interface IService{ [OperationContract] string Method(MyMessage message);}public class Service : IService{ public string Method(MyMessage message) { return "Hello: " + message.name; }}
The problem is that message contracts cannot be used at the same time as other parameter types. In this case, the return value of the operation is a string. Return values are just another output parameter, so this operation is mixing a message contract message with a primitive parameter type. This fails because message contracts give you control of the layout of the SOAP message, preventing the system from melding in these additional parameters.
By the way, the error message you get when you try to mix message contracts looks like this.
System.InvalidOperationException: The operation 'Method' could not be loaded because it has a parameter or return type of type System.ServiceModel.Channels.Message or a type that has MessageContractAttribute and other parameters of different types. When using System.ServiceModel.Channels.Message or types with MessageContractAttribute, the method must not use any other types of parameters.
Next time: Controlling the Synchronization Context
Secure calls to a hosted service are intermittently failing with the following error message:
An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.
The inner exception looks like this:
The message could not be processed. This is most likely because the action '*' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.
Why are these calls failing?
A sometimes overlooked aspect of hosted services is that the host controls the service lifetime. If you host your service in IIS, then it is possible that the application domain your service resides in will eventually be recycled. For instance, you may touch a configuration file that causes IIS to stop and restart all of your web services. When this occurs, the next call to the web service creates a fresh instance that knows nothing about any past security contexts that you may be using. These kinds of situations can cause the above error message because the service is not expecting a secured message and doesn't know how to send back a secured fault.
Next time: Mixing Message Contract Attributes
The first step in tuning a service is figuring out which throttles should be adjusted. The default throttle values for WCF are extremely conservative out of the box, meaning that you almost always will be tuning throttle values upwards. This also means that you can get a lot of information from running your service with a predictable load and identifying the throttles that are being hit.
Unlike many quota settings, there is no obvious impact to hitting a throttle. Instead, requests will get bunched up at the throttle points, causing your entire service to appear slow even though you aren't using all of the available resources of the machine. Quota setting problems are easier to diagnose because requests simply fault instead of just taking a long time. You can identify throttle setting problems by enabling application tracing. Most throttles will trace at the Information level when the throttle value is exceeded. Here's an example configuration file for enabling Information level tracing in your service.
<configuration> <system.diagnostics> <sources> <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true"> <listeners> <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "c:\servicelog.txt" /> </listeners> </source> </sources> </system.diagnostics><configuration>
Next time: Dangers of Application Domain Recycling
During the server upgrade a while back, there was a settings change that caused wide content to get cut off rather than displaying scroll bars. There pretty frequently are some long lines in the code samples that won't fit on the average display. I guess they were trying to encourage everyone to go out and buy larger monitors. I've tried out a few different scrollbar placements to avoid this problem. The one I settled on was to put scrollbars on each code block as needed so that you don't have to move the mouse so much to look at a particular listing. The other alternatives that didn't look bad were to put one set of scrollbars at the bottom of each post containing a long listing or to just use the browser scrollbars. I'm open to suggestions if you're particularly fervent.
I'm writing a middle-tier service that needs to act as the client. I can get the user name from the client credentials but the password isn't available. How do I get the client's password?
Most reputable security systems never give the service access to the client's password. What they do give the service is the client's identity and some token that provides proof that the client is who they claim they are. There's no way to pass that token on without cooperation by the security system. This cooperation process is called credential delegation. I've talked about delegation of credentials in the past and shown how to impersonate with delegation.
Alternatively, you can use a security system that does not protect the user's password. HTTP basic authentication sends the user's password to the service, allowing the server to do whatever it wishes with that password. Similarly, you can specify user name and password client credentials for message security but set EstablishSecurityContext to false. This lets the client send message security credentials without the intermediary consuming them. If you use this approach, you should enable transport security to prevent other people from reading the client's password during transmission.
Next time: Tuning Service Throttles
Due to the holidays, there will be no posts on Thursday or Friday of next week. There will be posts Monday through Wednesday, but I may not always be approving/responding to comments or answering email until the week after.
I'm getting this error message even though I have security enabled for my service:
Unhandled Exception: System.InvalidOperationException: The response message must be protected. This is required by an operation of the contract ('ICalculator', 'http://Microsoft.ServiceModel.Samples'). The protection must be provided by the binding ('CustomBinding', 'http://tempuri.org/').
This is sometimes a symptom of incorrect layering between security and composite duplex. Composite duplex correlates two channels together. If the security binding element is below composite duplex in the channel stack, then you'll get this error message because the security channel that is protecting the requests is not able to protect the responses that come in along the back channel.
The solution is to reverse the ordering and put security on top of the composite duplex channel. Additionally, you need to specify the use of SecureConversation for that security channel. The security method that you are actually using (user name/password, certificates, Kerberos, whatever) should be specified as the bootstrapping method for the secure conversation. Here's an example of a server with the right layering.
CustomBinding binding = new CustomBinding();SecurityBindingElement security = SecurityBindingElement.CreateAnonymousForCertificateBindingElement();binding.Elements.Add(SecurityBindingElement.CreateSecureConversationBindingElement(security));binding.Elements.Add(new CompositeDuplexBindingElement());binding.Elements.Add(new OneWayBindingElement());binding.Elements.Add(new TextMessageEncodingBindingElement());binding.Elements.Add(new HttpTransportBindingElement());ServiceHost host = new ServiceHost(typeof(CalculatorService), new Uri("http://localhost:8000/"));host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "localhost");host.AddServiceEndpoint(typeof(ICalculator), binding, "");host.Open();Console.WriteLine("Press <ENTER> to terminate service.");Console.ReadLine();host.Close();
Next time: Getting the Client's Password
It's occasionally useful to be able to replace the binding being used for an existing service host. For example, if the binding was loaded from configuration, you may then want to have your code examine the binding and modify some of the settings. This lets you use the configuration system without any extensions, while still having control over the settings used from the configuration file.
Access to the service binding is available through the service description. The binding for an endpoint can be changed as long as you haven't started using the service by opening it. This example shows picking out the endpoint to modify using the contract type. There are several other options you can use to identify an endpoint.
ServiceEndpoint endpoint = host.Description.Endpoints.Find(typeof(IService)); BindingElementCollection elements = endpoint.Binding.CreateBindingElements(); elements.Find<TransportBindingElement>().MaxReceivedMessageSize = 5000; endpoint.Binding = new CustomBinding(elements);
It's important to notice here that we aren't just altering the binding that is already present. The setting in this example is one that will be regenerated every time the binding creates a new set of binding elements. That means that we have to capture a snapshot of the binding, modify the snapshot, and then set that as a custom binding for the endpoint.
Will the XML DOM I get from a message exactly match the XML DOM that was originally sent?
This isn't a real question I've seen, but it's often hidden inside of another question. For example, there are people that extract content from an XML document by building a DOM and taking the contents of the fourth child of the second child of the root node as a string. This is a really bad idea. There are all kinds of subtly different trees of nodes that can be built from even a simple XML document.
Here's one example. Take this program that reads an XML document and starts printing out its text nodes.
string body =@"<poem> 'Twas brillig, and the slithy toves Did gyre and gimble in the wabe; All mimsy were the borogoves, And the mome raths outgrabe. 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!' He took his vorpal sword in hand: Long time the manxome foe he sought-- So rested he by the Tumtum tree, And stood awhile in thought. And as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! One, two! One, two! And through and through The vorpal blade went snicker-snack! He left it dead, and with its head He went galumphing back. 'And hast thou slain the Jabberwock? Come to my arms, my beamish boy! O frabjous day! Callooh! Callay!' He chortled in his joy. 'Twas brillig, and the slithy toves Did gyre and gimble in the wabe; All mimsy were the borogoves, And the mome raths outgrabe.</poem>";reader = XmlReader.Create(new StringReader(body));while (reader.Read()){ if (reader.NodeType == XmlNodeType.Text) { Console.WriteLine("[TEXT]"); Console.WriteLine(reader.Value); }}
[TEXT] 'Twas brillig, and the slithy toves Did gyre and gimble in the wabe; All mimsy were the borogoves, And the mome raths outgrabe. 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!' He took his vorpal sword in hand: Long time the manxome foe he sought-- So rested he by the Tumtum tree, And stood awhile in thought. And as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! One, two! One, two! And through and through The vorpal blade went snicker-snack! He left it dead, and with its head He went galumphing back. 'And hast thou slain the Jabberwock? Come to my arms, my beamish boy! O frabjous day! Callooh! Callay!' He chortled in his joy. 'Twas brillig, and the slithy toves Did gyre and gimble in the wabe; All mimsy were the borogoves, And the mome raths outgrabe.
One block of text went in and one text node came out. Now, what happens when all we do is write that XML into a message body and then read it back out again? I've kind of spelled out what's going to happen as early as the title of this post already, but try to guess the exact output.
reader = XmlReader.Create(new StringReader(body));message = Message.CreateMessage(MessageVersion.Default, "", reader);reader = message.GetReaderAtBodyContents();while (reader.Read()){ if (reader.NodeType == XmlNodeType.Text) { Console.WriteLine("[TEXT]"); Console.WriteLine(reader.Value); }}
[TEXT] 'Twas brillig, and the slithy toves Did gyre and gimble in the wabe; All mimsy were the borogoves, And the mome raths outgrabe. 'Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun[TEXT] The frumious Bandersnatch!' He took his vorpal sword in hand: Long time the manxome foe he sought-- So rested he by the Tumtum tree, And stood awhile in thought. And as in uffish thought he stood, The Jabberwock, with eyes of flame,[TEXT] Came whiffling through the tulgey wood, And burbled as it came! One, two! One, two! And through and through The vorpal blade went snicker-snack! He left it dead, and with its head He went galumphing back. 'And hast thou slain the Jabber[TEXT]wock? Come to my arms, my beamish boy! O frabjous day! Callooh! Callay!' He chortled in his joy. 'Twas brillig, and the slithy toves Did gyre and gimble in the wabe; All mimsy were the borogoves, And the mome raths outgrabe.
The nodes coming back from the reader are totally different even though the XML content is exactly the same once everything is pasted together. In this case, WCF chunks text nodes every 256 bytes to avoid making potentially unbounded memory allocations.
Next time: Building a Secure Composite Duplex
I've been told that I'm exceeding the maximum number of items that can be serialized or deserialized. Where is this MaxItemsInObjectGraph setting? I can't find it anywhere.
MaxItemsInObjectGraph looks like a message encoder setting but you won't find it on any of the bindings or message encoder binding elements. You also won't find it on any of the transports or channels. That is because the MaxItemsInObjectGraph quota is actually applied to the serializer that the service uses for a particular operation. You can access this setting through a data contract serializer behavior that modifies how the service or operation works.
In configuration, you can change this setting by adding a custom behavior to the behaviors section that includes the following setting.
<dataContractSerializer maxItemsInObjectGraph="3" />
You can also change this programmatically by modifying the operation description of your service. You'll need to change this code snippet with the appropriate endpoint and operation name.
OperationDescription operation = host.Description.Endpoints[0].Contract.Operations.Find("MyOperationName");operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 3;
Note that you cannot just create a new instance of the behavior and add it to the description. There is a limit of having only one DataContractSerializerOperationBehavior per operation and the operation comes with one by default.
One unusual aspect of this quota is visible in the original question. The quota setting applies to both serializing and deserializing a message. This means that you have to modify the setting on both the client and server side for this to work.
Next time: Splitting Up XML Text Nodes
This time it's two questions that have the same answer.
What contract does the message encoder have for producing a message from ReadMessage?
What should the transport do if the message encoder doesn't produce a message from the buffer you give it?
The contract of the message encoder is that it will always either throw an exception or produce exactly one message each time ReadMessage is called. This means that a properly-written message encoder will never fail to produce a message without throwing an exception out of ReadMessage for the transport to handle.
As you might recall, the contract that the transport must abide by is that operations should only throw exceptions that are subtypes of CommunicationException, TimeoutException, or some fatal exception type (such as OutOfMemoryException). The transport should catch all exception types that it knows the message encoder will produce, such as XmlException, and wrap those in some instance of CommunicationException. A good choice would be ProtocolException. However, the transport should not just eat all types of exceptions. It's best to let a stray exception through unless it is a specific, known type because you run the risk of trapping a fatal exception.
What happens to the message after the transport gets it back from the message encoder is no longer constrained by the contract of the message encoder.
Next time: How to Configure MaxItemsInObjectGraph
I didn't originally intend to draw out the picture corresponding to TryReceive and WaitForMessage in the presence of transactions. However, I had just upgraded Office 2007 to the final version and I wanted to make sure that everything was still working. I freehand draw all of these illustrations on my tablet in OneNote. The only change recently has been to use a thicker pen. The thick pen makes the line work look a lot nicer although the small printed text is a little blurrier than I like. I use GIMP to crop and save the images afterwards.
This is a case where having a picture makes a subtle point in text look really obvious.
When you call receive on a channel, there is always a timeout that bounds that receive operation. There are actually three different kinds of receive on the standard input channel shape. The Receive method waits for a message to arrive up to the timeout period and then throws an exception if no message actually comes. Most of the time, this receive behavior is what you want to build around. Give Receive as much time as you can afford and then simply fail if no messages show up.
The second kind of receive, TryReceive, is similar to the standard Receive but with a soft failure mode. Instead of indicating the failure to receive through an exception, TryReceive has a boolean return value that indicates whether the operation succeeded. A successful attempt to receive provides you with the message as normal. If you can't effectively recover from a lack of messages, then you should probably be using the basic Receive. If there is some way for you to recover, then TryReceive allows you to avoid the expense of throwing and catching the TimeoutException.
The final type of receive, WaitForMessage, is essentially a peek operation. Like TryReceive, WaitForMessage uses a boolean return value to indicate whether the operation succeeded. However, WaitForMessage never returns a message to you. It simply says that if you had actually performed a Receive operation, then you would have seen a message arrive before the timeout expired. Waiting for a message can be used to defer work until a message is ready for processing. One example of this type of work deferment is the receipt of a message inside of a transaction. Suppose that you had a loop checking for messages to arrive. If you just called Receive or TryReceive, then you would need to start a transaction every time through the loop in case a message showed up. Each time a receive attempt failed, the transaction would have to be canceled. With WaitForMessage, you could instead peek for messages and then only start a transaction when you knew that a message was likely to be there.
Next time: Handling Message Encoder Errors
I was home sick yesterday, so after publishing the WCF RTM announcement, I decided to flip through and read everyone else on MSDN that published a similar announcement. Here's the list I came up with. The order is just the order I found them in. The links go directly to the announcement messages.
I stopped looking after finding the first twenty! There is a lot of buzz around having gotten this release out the door. It's going to take a few days to see the trickle down through external sites and get a reaction to the final product.
After a long wait, WCF V1 is now available! We will of course be shipping with Vista, but the online download is accessible now. Everyone should be upgrading from the beta and RC releases now. Remove any previously installed versions before attempting to upgrade.
Here are the download materials:
You can also get the Visual Studio Orcas and workflow extensions corresponding to this release.
Here's a quick list of things to try when debugging a non-functioning SSL server certificate.
Next time: When to Wait for Messages
There are two architectural models for moving messages through a system. Pull messaging models require the receiver to actively suck messages out of the pipeline in order to achieve flow. If the receiver is not willing to perform work, then there's nothing the sender can do to move messages around. Push messaging models automatically generate work on the receiving end when a sender transmits a message. It's then the responsibility of the receiver to process these work items before system capacity is reached (in many systems, there is some programming ease-of-use to make the work items automatically expire after some period of negligence by the receiver). Real messaging systems have many architectural layers stacked on top one another, some of which are push and some of which are pull. Just the process of sending a packet of data using TCP requires several protocol layers of pushing and pulling.
You may have noticed that the channel stack of WCF represents a pull model. Actually, you may not have noticed this because the service layer of WCF represents a push model. Even some parts of the channel stack push instead of pull. For instance, the arrival of new client connections at an endpoint is a push operation. Clients will attempt to connect even if the service is not ready to listen for them. However, the service has to engage in some pulling to transform those client connection attempts into transport channels. The boundary from a push layer to a pull layer is a queue. Quota settings on the queue define the system capacity for how much outstanding work is tolerated and how long work should wait in the queue before being expired. The boundary from a pull layer to a push layer is a message pump. Quota settings on the message pump define how aggressively the pump operates.
The channel stack uses a pull model because it's very convenient from a framework perspective. Pull models allow the user to explicitly control resources without having to define lots of complicated policy. Work only happens in a pull model when the user takes action, so the messaging system can simply idle when it doesn't have the capacity to accept additional work. Pull models are also convenient for error handling because there is always user code to which we can report any errors. If we don't have user code, then we need policy to dictate how errors are handled. Whenever you're writing channels, you need to keep the pull model in mind or else you will end up writing lots of fragile layer transition code as you go back and forth from push to pull. Try to normalize to pulling as low as possible in the stack.
Services use a push model because it's very convenient from a programming perspective. Nobody wants to write message pumping and dispatch loops. Programmers want to simply specify what their messaging handling logic is and let the system figure out when that logic should be invoked. Services normalize to the push model at the very top of the stack, above all of the channels.
Next time: Dealing with SSL Certificate Validation Failures
Once again I ended up with a picture laying around after writing yesterday's article on addressing. This picture covers all of the basic addressing cases that I discussed.
The picture really clearly shows the distinguishing feature of anonymous and directed addressing. Anonymous addressing follows a single arc going from client to server to client. Directed addressing follows one arc going from client to server and a separate arc going from server to client. Mixed-mode addressing of course has at least one path of each type.
WCF has a variety of addressing controls for specifying where messages should be sent. For example, there's the To address of the logical endpoint, the Via address of the physical endpoint, the ReplyTo address of the endpoint where the response should go, and so on. In most simple cases, it's not necessary to actually specify all of these addresses. There's a single party to the conversation to which you send all of your messages. And, that other party knows that it should send all of its messages to you regardless of whether those messages are replies, faults, or acknowledgments. There are three addressing patterns that capture these kinds of relationships.
Anonymous addresses are the simplest form of addressing. Anonymous addressing is used when there is an inherent logical path for a response. TCP is a bidirectional communication transport. Where should I send a response to a TCP message? Well, a good guess is back to whoever is on the other side of the socket that sent me the message in the first place. I don't have to think about what that person is called. Similarly, the request-reply model of HTTP means that there's always an obvious destination for responses. You have one chance to use the HTTP reply channel and using it also doesn't require you to know where the messages are going.
Directed addresses cover the case where sending the response requires creating a new channel for communication. With dual HTTP, the client creates one HTTP request to send a message and then the server needs to create its own HTTP request to send a response. Since the server is initiating the send, it needs a specific endpoint to establish a connection. You have to give the server the address of some endpoint for the response. One-way messaging also requires directed addressing because there's no back channel for communication. If the server wants to send a message back, that's a completely separate operation from the first message as far as anyone's concerned.
WCF supports either anonymous or direct modes of address for any particular binding. The common TCP and HTTP bindings always use anonymous addresses and the less common dual HTTP binding always uses directed addresses. However, there is a third form of addressing that sometimes uses anonymous addresses and sometimes uses directed addresses. Mixed-mode addressing combines anonymous and directed addresses depending on the message that is being sent. A typical example of mixed-mode addressing is the use of a dedicate machine for processing fault or acknowledgment messages. If the standard exchange sequence for replies is HTTP or TCP, the responses use anonymous addressing but the faults use directed addressing. Using mixed-mode addressing requires a lot of fiddling at the level of channels because it does not compose nicely with the service-oriented view of messaging.
Next time: Pull Not Push
This is just a style convention that helps you avoid doing some thinking while writing custom channel classes. During the channel construction process, there's a flow of information from the binding (design time), through the channel factory and listener, and down to the channel (run time). The channel needs to know about the configuration changes that the user has made in setting up the binding. As we've seen before, there's some difficulty with storing this information outside the channel, so we can't rely on referencing the information indirectly through another object after creation. Here's the convention that we've sort of settled on in most of our channels.
When creating the channel factory or listener (jointly referred to as the channel manager), the constructor takes two arguments.
When creating the channel, the constructor takes as many arguments as it needs to pass all of the private data that was being stored in the channel manager. It can be helpful to group some of these arguments using a specialized interface if you need to pass around the same information to a lot of different places. The channel manager does not give the this instance to the channel normally. An exception is if you're using the ChannelBase class for your channel, which requires an instance of ChannelManagerBase. In that case, the channel manager gives its this instance to the channel solely for that purpose. The channel constructor takes that instance as a ChannelManagerBase rather than using a specialized type.
Next time: Mixed Mode Addressing