|
|
Browse by Tags
All Tags » Bindings » Channels » Indigo (RSS)
-
The basis of a channel stack is that there is a series of objects that share a common interface for communication. This leaves message encoders with something of a problem as the primitive operations for encoding and decoding messages are different than the primitive operations for sending and receiving messages. Message encoders avoid this problem by being contained within a channel rather than acting as a peer in the channel stack. However, this is different than the model used for bindings, which make the message encoding binding element a peer of the other channel binding elements. To make things harder, bindings use a "no lookahead" construction process where constructing an object cannot speculate about future construction by looking into the unprocessed information in the binding. That results in a subtle dance between a message encoder and a channel that wants to use a message encoder. During the construction process, a binding gives you only a context for storing computed information and the ability to initiate the next phase of the construction process. When we go to build a message encoder, it's not possible to actually build anything because the channel that will hold the message encoder doesn't exist yet. The message encoder doesn't know how or why it is going to be used. Instead, what a message encoding binding element does to build is add itself to the BindingParameters in the context. The message encoding binding element then initiates the next phase of the construction process. At some point in the future, a channel may look at the context to see if it contains a previously saved binding element, which can now be built. The delay in instantiation is what allows channels to have a different order for physical containment than the logical order of the binding elements. Next time: Quotas for Copying Messages Read More...
|
-
What channels can be used in a context binding? The primary limitation for building a context binding is that the channel stack has to have the right shape. The context exchange protocol used by a context binding requires that the first invoked operation be a request-reply operation. This is so that the initial context can be established. In order to support a request-reply operation, the channel stack needs to support one of a particular set of shapes. There are currently five channel shapes allowed when using a context binding: IRequestChannel IRequestSessionChannel IReplyChannel IReplySessionChannel IDuplexSessionChannel The request and reply channel shapes are paired for the client and server so on any particular endpoint there are three valid channel shapes. Conditions are limited further if you want to use HTTP cookies as your context exchange mechanism rather than the default of SOAP headers. In that case it's no longer possible to use a duplex channel so you're limited to variations on the request-reply message exchange pattern. Next time: Manual Context Management Read More...
|
-
I've done a bit of grouping for the remaining binding elements as there are fourteen non-transport binding elements that I'm covering in this list. I've pointed out the ones that respond to a type with GetProperty on the base class as opposed to repeating the same code in each subclass. Our standard message encoders respond to two types, although only one is on the base class. These two interfaces will override the ones given by the transport if a message encoder is in the binding. The transport delegates to the message encoder before giving its useless default response. MessageVersion (on the message encoder base class) XmlDictionaryReaderQuotas (on the Text, MTOM, and Binary encoders) The one-way and transaction channels both support just a single interface. ChannelProtectionRequirements All of the security binding elements support a pair of interfaces and the actual security channels add an additional type. ISecurityCapabilities (on the security base class and on the Windows and SSL stream upgrades) IdentityVerifier (on the security base class and on the Windows and SSL stream upgrades) ChannelProtectionRequirements (on the asymmetric, symmetric, and transport security binding elements) The reliable message binding element supports a pair of interfaces as well. ChannelProtectionRequirements IBindingDeliveryCapabilities Finally, the composite duplex binding element has a pair of types. If you're curious why composite duplex is interacting with a security interface, then you should read the earlier article on layering between composite duplex and security . ISecurityCapabilities ChannelProtectionRequirements Next time: Starting a Hosted Service Read More...
|
-
I've created a custom implementation of GetProperty for my binding but now I'm getting errors when I go to use the channels. Why is the validation for these channels failing? This is an implementation problem that I've talked about in the past. There is a requirement that the values queried from design time objects, such as bindings and binding elements, match the values queried from runtime objects, such as a channels. If the two don't agree on a property value, then you can experience problems ranging from an error creating the channel to mysterious failures sending and receiving messages. This problem most commonly happens when you override an existing property value on the binding but forget to override the property in the same way on the channels. Use this picture illustrating GetProperty to follow the chain of property values. However, this problem can also happen even when you're not overriding an existing value. If you write a GetProperty implementation but forget to delegate to the inner channel or binding element, then the chain of GetProperty calls terminates right there. Any further channels or binding elements do not get to contribute to GetProperty evaluations. This can easily cause a discrepancy between the design time and runtime values of a property despite the fact that you didn't explicitly modify that property. In most cases, this is a severe enough problem to fail very quickly. If you've written a GetProperty method and are suddenly seeing property value mismatches for properties that you didn't touch though, then make sure that your GetProperty method is delegating any unhandled properties to the right place. Next time: Preventing Anonymous Access Read More...
|
-
The story from yesterday: there is an important setting for composite duplex that is only settable through the binding context. Unfortunately, proxy clients automatically create and use their own binding context so there is no convenient time to poke in a replacement value for the setting. What kind of a workaround can we come up with? Since there is no convenient way to intercept the binding context at the producer, we'll instead need to intercept the binding context at the consumer. The consumer of the binding context is the channel construction process of the binding. In particular, we need to modify the ListenUri setting before we reach the BuildChannelListener method of the composite duplex binding element. That means our opportunities for interception are going to be in methods such as CanBuildChannelFactory, CanBuildChannelListener, BuildChannelFactory, and BuildChannelListener. The binding context instance gets passed along from binding element to binding element so it is safe to modify the setting at any opportunity along the way. We don't have to worry about finding the correct instance of the binding context. Every instance that we see is one that we want to modify. The solution that I came up with for this problem was to write a binding element that modified the ListenUri as the binding context went by. Other than this change, the binding element simply delegates every method to the next binding element down. You can position the binding element in the channel stack so that your customization is always reached before the composite duplex binding element. The binding context that composite duplex receives contains your modifications, giving you full control over the ListenUri setting that was otherwise hidden. This solution is generally reusable for other situations where you need to modify the binding context or channel construction process. I won't say that there are many such situations, but it is a tool for you to use. An interesting coincidence about this problem was that two different people on consecutive days with different scenarios were looking for a solution. Mike Taulty was the second person and he's done a write up of why he was interested in composite duplex and the code I gave him for the ListenUri modifying binding element . Mike added configuration support, which I hadn't bothered with. From configuration, you'll need to build out a complete custom binding. From code, it's simpler because you can start with an existing binding and Read More...
|
-
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. The constructor gets the this instance of the binding element that is building the channel manager. Inside the constructor, the configuration settings of the binding element are copied to private fields of the channel manager. The channel manager doesn't hold on to the binding element after initialization is complete. The constructor gets the binding context instance that the binding element was passed. The binding context instance allows the channel manager to fish out the inner channel manager and access binding parameters. 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 specializeed 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 Read More...
|
-
I drew this picture for myself while working on the guidelines for implementing GetProperty . I figured that other people might find it useful as well. One of the guidelines is that queryable properties on design time objects should flow to the corresponding run time objects. The black boxes show the classes that support GetProperty and the black arcs show the anticipated flow of properties. The red boxes show the classes that don't support GetProperty today but might make sense to have support in the future. Read More...
|
-
This post is just some quick thinking about guidelines for implementing the GetProperty method. These guidelines are still in development so think of this as a draft rather than real guidance at this time. Background: We provide an extensibility point called GetProperty on many of the components you can build using the channel model. The exact list of components that support GetProperty are bindings, binding elements, channel factories, channel listeners, channels, and message encoders. GetProperty allows someone to execute a strongly-typed query against your component to inspect its configuration settings. GetProperty takes a type parameter T and either returns some instance of T or returns default(T) to indicate that the type is unknown. DO expose configurable settings for your component using GetProperty. GetProperty should be used in preference to ad-hoc methods for searching through a stack of components. DO NOT require the use of GetProperty to access mandatory or intrinsic configuration settings. The types supported by GetProperty are not discoverable and any setting that your component considers mandatory should be accessible through the object model. GetProperty can be used as an alternative way of accessing the same value. DO support in your runtime objects every property that was available on your design time objects. If a channel factory exposes a setting, then every channel produced by that factory should expose a corresponsing setting that tells you what the value was when the channel was created. DO create specialized interfaces that capture each class of information that you want people to query on. Specialized interfaces promote the reuse of a particular type for semantically identical settings. DO reuse existing interfaces if your information has exactly the same semantics as the previous use. Conversely, if your settings don't have the same semantics, don't reuse a type just because it's more convenient to do so. DO NOT key properties off of commonly used types with a generic meaning. Types that appear frequently, such as IDisposable, will not have consistent semantics for all of their potential uses. DO NOT key properties off of value or enumerated types. We enforce this by placing a restriction on the generic type parameter. DO delegate down to inner channels, channel factories, and channel listeners when they exist and your component does not know about the requested type. We have a pipeline model that supports the composition of many Read More...
|
-
We spent a lot of time before the last release looking for parts of the framework that either didn't work or were unnecessary to get the job done. An amazing amount of cruft can build up in a design over time. A great idea or new feature is often accompanied by several supporting pieces of infrastructure to make the feature work. When that feature is later changed or removed, those supporting pieces often mutate into some other purpose rather than going away. Cleaning out those extra bits now means that we won't have to support them for years to come. Here are ten bits of the channel framework you may or may not have noticed disappeared in June. The InnerChannelListener property was removed from ChannelListenerBase. Use GetProperty instead to run queries on the channel stack at run time. The Identity property was removed from IChannelListener. Use GetProperty<EndpointIdentity> to access this instead. The MessageVersion property was removed from IChannelManager. Use GetProperty<MessageVersion> to access this instead. The Scheme property was removed from IChannelManager. There were a few implementations that needed this property, and those specific channels still have a Scheme property on their factory and listener. The Manager property of IChannel was removed. If you use the ChannelBase class, your implementation will still have a reference to the manager, but the property is now protected by default. We got rid of everything on the IChannelManager interface so we just pitched the whole thing. There's still a ChannelManagerBase class for you to extend but that's purely for convenience. The ChannelManagerBase class was slimmed down by removing the AbortChannels, CloseChannels, BeginCloseChannels, and EndCloseChannels methods. All of these methods were part of a channel lifecycle management system that clashed with our guidance for controlling channel resources. We've tried to not tie the lifetime of a channel up with the lifetime of its factory or listener. The EventSender property and constructor were removed from CommunicationObject. This was a very infrequently used feature that was causing problems for some channel implementations. The UnhandledBindingElements collection was removed from BindingContext. Add any information to the BindingParameters collection instead on the BindingContext and use Find or FindAll to search through the parameters later. This means there's only one place to search now instead of two. Each binding element had a BindingElementConverter Read More...
|
-
Yesterday's post covered most of the big new features that were added in the latest release . Today I'll go through the rest of the new features that are smaller in scope although no less exciting. #1: When the channel stack is being built from binding elements, some binding elements want to know what elements are underneath of them so that they can properly configure themselves. Previously, there was no way for custom binding elements to get at this information. We made the RemainingBindingElements property on the binding context public so that your binding elements can work exactly the same as ours. #2: Transport stream upgrades frequently operate on a point-to-point basis, but the API for providing stream upgrades previously only gave the upgrade provider the final address of the connection. We've changed the interface for StreamUpgradeProvider so that upgrades can see both the endpoint address and the via address of the next hop. #3: It's now possible to disable the use of HTTP keep alive. We added a KeepAliveEnabled option to HttpTransportBindingElement with the default set to enabled, which was the old behavior. This option is only available on the binding element so you'll need to use a custom binding if you need to change this setting. #4: There's now a quota setting for how long a connection can take to authenticate. A client needs to send a few hundred bytes of data before the server has enough information to perform authentication. Previously, the client had the entire receive timeout in which to send this data. The header is often much smaller than a normal sized message and clients are anonymous until this information is processed. The ChannelInitializationTimeout on the binding element limits the amount of time a malicious client can tie up one of the connections for your server. We also changed a few interfaces into abstract base classes although we didn’t add any new functionality to those classes at this time. The IRequestContext interface is now the RequestContext class and the IStreamUpgradeBindingElement interface is now the StreamUpgradeBindingElement class. I had a list of changes that I was hoping to get through during this week. However, the first two days ran a little bit long so there are still a few more items to cover. I'll run one more installment of this series on Monday and the next set of topics will start after the 4th of July holiday. Next time: Some Changes for Channels and Transports in the June CTP, Part 5 Read More...
|
|
|
|