|
|
Browse by Tags
All Tags » Channel Extensi... » Transports (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...
|
-
Inside a service, there's a fundamental loop running whose job it is to create channels for the incoming connections to the service. There's another loop that runs later, which you may argue is equally fundamental, that reads messages from each channel to determine the actual service invocation. Every one of these service requests though was preceded at some point by a channel being accepted (one channel may produce multiple requests of course). Depending on how things are configured, the service may be running a transactional loop or a non-transactional loop. The transactional loop runs when the service needs to create its own transaction for reading messages. As a custom channel author, the two loops have different implications for how your channel gets used. In the non-transactional case, the service sits in a loop calling BeginAcceptChannel on the topmost channel listener. This loop continues until the listener fails to give back a channel or the listener faults. The loop pauses if a quota is reached that prevents more channels from being accepted, but the loop can later be restarted when the quota is no longer an issue. In the transactional case, the service first sits in a loop calling WaitForChannel. When WaitForChannel completes, the loop creates a new transaction and calls AcceptChannel. The use of WaitForChannel is an optimization to reduce the number of unnecessary transactions that get created. The loop will later complete or abort the transaction as appropriate but otherwise functions very similarly from this point. Next time: SOAP Extensions Read More...
|
-
Let's fill in some of the spaces around yesterday's checklist with a list of additional features for a custom channel. Nothing that's been added to this list is required to actually send or receive messages. By doing the things listed here, you can enable some additional scenarios and make your channel easier to use. However, if you're looking to write a channel as cheaply as possible, then these are the features that you might consider cutting. I'll summarize the previous list using italics and interlace the descriptions of the new checklist items. Understand why you're writing a channel. Identify whether the channel you need is a protocol channel or a transport channel. Identify the channel shapes that your channel needs to be able to surface. Write a binding element so that your channel can plug into the build process. Add configuration support to your binding element. Configuration allows the settings of your binding element to be specified through XML files rather than through imperative code. You implement this configuration support by writing a binding element extension that duplicates the property settings of your binding element in a format that can be picked up by the configuration system. You will quickly grow tired of performing this duplication by hand and start thinking about how this process can be done automatically instead. Write a standard binding that demonstrates the proper usage of your binding element. A standard binding represents the stacks of binding elements for your core scenarios along with the most commonly used configuration settings for those binding elements. Creating a standard binding allows people to frequently make use of your channel without having to write a custom binding of their own. Support generating and consuming policy assertions that describe the capabilities of your binding element. Policy assertions allow you to advertise particular features of your channel so that the two sides can coordinate ahead of time about how the channel stack should be constructed. Policy support is implemented through a pair of interfaces for policy import extensions and policy export extensions. Write a client channel factory that can produce instances of your channel for use by client applications. Write a service channel listener that can produce instances of your channel for use by service applications. Write channel instances to cover each of the supported channel shapes. For transport channels, add a description of your supported Read More...
|
-
This is the start of a long series on channel development. Some of the material in the series is going to duplicate topics that I've written about in the past. That's ok. The goal of the series is to have a walkthrough that is self-contained and in one place that is easy to read through. Many of those older articles are for older versions of WCF and may differ slightly from what was shipped in the final version. Everything in this series is going to talk about the V1 version of WCF. As an added bonus, everything here should still be true in the next version of WCF and future versions after that. This is the advantage of having to live with backwards compatibility. Future versions of WCF might make it easier to do the things that I talk about, but the methods in this series should continue to work forever. In the end, it should be possible to stitch the articles in this series together into one massive blob of text although I probably won't go that far. Here's what the series is going to cover: Background on the role of channels WCF and the channel model architecture Basic walkthrough of writing channels Writing a simple protocol channel Advanced walkthrough of writing channels Writing a simple transport channel Specialty topics for writing channels The earlier topics consist of 4 or 5 articles each. The later topics consist of around 10 articles each. As you can see, this is going to be a really long series in total. To counter that, I'm not going to run articles in this series all 5 days a week. You will probably get 3 articles of this series per week mixed in with other unconnected topics. Here are the four articles in topic #1: The Introduction (that's this article you're reading now) When to Write a Channel Protocol Channels Transport Channels I'm not going to do an introduction article for each topic so topic #2 starts directly in the fifth article. Next time: When to Write a Channel Read More...
|
-
I occasionally see people asking how they can fake the security capabilities of a binding. These questions often start off with "I'm getting an error message that a message's required protection level is not being met". Now, I'm not precisely sure why you'd want to fake the security capabilities in this case. After all, the application developer is in charge of both specifying the protection requirements of the messages and choosing what channels to use. If they're getting this error message, then it more than likely means that this helpful check has detected a problem somewhere in their design. There are a few rare reasons why you'd want to fake this, but they mainly involve transmitting over specially secured networks. However, it turns out that faking security capabilities is exactly the same as legitimately specifying the capabilities of a custom channel so I might as well explain that! Security capabilities are found by querying the channel stack with GetProperty for an instance of ISecurityCapabilities. This call should be supported on the binding element of channels that implement message or transport security. Transport channels should respond with something, even if it is to say that they don't support any kind of security. Everyone else can just delegate the call to their inner channel (which is typically what you do by default for any type you don't know about). public interface ISecurityCapabilities { ProtectionLevel SupportedRequestProtectionLevel { get; } ProtectionLevel SupportedResponseProtectionLevel { get; } bool SupportsClientAuthentication { get; } bool SupportsClientWindowsIdentity { get; } bool SupportsServerAuthentication { get; } } The fields here should be self-explanatory, you either support a particular feature or you don't, but let's look at examples from some of the existing channels. HTTP doesn't support any protection on requests and responses, neither encryption nor signing. HTTP supports client authentication when in any security mode but Anonymous. It only supports server authentication when using Negotiate security. Windows identities are supported whenever client authentication is. On the other hand, HTTPS provides both encryption and signing for both requests and responses. HTTPS always does server authentication. It supports client authentication and Windows identities whenever HTTP would plus whenever client certificates are turned on. You can quickly get a sense of the differences between HTTP and HTTPS by looking at 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...
|
-
Datagrams are a self-contained unit of data. Each datagram carries with it the routing and context information needed to receive the data without knowing about any earlier exchanges of information. This means that you can continue sending datagrams from a source to a destination even if past datagrams along this path have been lost, duplicated, or misdirected. The protocol commonly associated with datagrams is the User Datagram Protocol (UDP) although it's possible to think of other transport protocols as having the same semantics as datagrams. For instance, when used in certain scenarios, queued transports and HTTP connections exhibit the same characteristics of datagram messaging as UDP. There is a particular pattern that you can use when implementing datagram channels in WCF. The singleton channel has a one-to-one mapping between channel listeners and accepted channels. When receiving datagrams, it doesn't make sense to have multiple outstanding channels listening at the same address. Any channel would be equally as good as any other for delivery precisely because datagrams are self-contained without reference to any earlier exchanges. This has led to the singleton model, where the channel listener only ever proceeds to accept one active channel. That channel has to hold its own state because even though the channel and channel listener are one-to-one, the channel listener may be destroyed before the channel . Of course, if that singleton channel is ever closed, the channel listener can accept a new channel in its place. However, this new channel is indistinguishably identical to the old instance, and there's always only ever at most one channel in existence. Next time: Advanced URL ACLing with Windows Vista 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...
|
|
|
|