Welcome to Windows Communication Foundation (WCF)
Top Tasks :

WCF Team Bloggers

Browse by Tags

All Tags » Channel Extensibility   (RSS)

  • Building with Encoders

    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...
  • Best Practice for Channel Shapes

    The hierarchy of channels derives from the single interface IChannel. By itself, IChannel is not particularly interesting because it doesn't introduce any new methods for communication. Each channel shape, such as IInputChannel or IDuplexSessionChannel, has its own interface derived from IChannel that describes the capabilities and semantics of the channel. When you write a channel, you may support variations of your channel for many different channel shapes. For example, you may support both an IInputChannel and an IOutputChannel variation for sending and receiving. Or, you may support both an IDuplexChannel and IDuplexSessionChannel variation depending on whether sessionful communication is needed. During the channel build process, your channel factory or listener will be asked to supply a single particular variation of IChannel. Since the variation is part of the generic contract, the concrete channel implementation that gets returned by the channel factory or listener must support the specified interface. Here are two best practices that specify more explicitly how that concrete channel implementation should work. Your channel factory or listener can't substitute an extended variation of a channel shape even though the type system lets you cast to the parent type. For example, IDuplexChannel and IInputSessionChannel both derive from IInputChannel. It would be wrong to return a duplex or sessionful channel if asked for an IInputChannel though. The build process is asking for the semantics of a one-way, non-sessionful input channel rather than just a type that has a callable interface compatible with IInputChannel. Use separate shape-changing channels if you need to adapt a channel implementation or supply a channel implementation that natively supports the correct shape. Each concrete channel implementation should only implement a single channel shape. While it's possible to write a single implementation that simultaneously supports multiple channel interfaces, you should instead have multiple channel implementations each supporting a single channel interface. The fact that you have different channel implementations for different shapes is hidden by the channel factory or listener so there's no additional complexity that the user of your implementation needs to worry about. Next time: Extensibility Read More...
  • Shutting Down a Channel

    A common corner-case in programming is what happens when multiple operations are attempted at the same time. One way to avoid the troubles of this corner-case is to simply prohibit having multiple operations occur simultaneously. However, it typically isn't possible to make this exclusion work in a universal fashion. Consider an object that prevents having multiple operations but permits having long-running (perhaps indefinitely long-running) operations. When faced with a long-running operation, it's desirable to have some way to prematurely stop that operation. The trick is that stopping an operation is often an operation in itself, violating the guarantee that only one operation runs at a time for at least a tiny period during shutdown of the object. This makes shutdown particularly prone to being a corner-case. Channels don't make any guarantees about the simultaneous execution of methods, but it can still be confusing to describe their behavior during shutdown. The basic operations of accept and receive are often long-running, meaning that there frequently is going to be some overlap between these operations and the end of the channel's lifetime. The accept or receive operation needs to have some outcome when it completes. How can that outcome be determined? Here's a rule of thumb to guess the behavior of any related method for a channel. This rule of thumb can be applied for example when shutting down the system or when a session finishes all of its input. If the operation is supposed to return some object, then that object is null. We didn't actually get an object instance during the operation. If the operation is conditional and reports whether it succeeded or failed, then the outcome is that it succeeded. A failure indicates that something went wrong, but there's nothing wrong with being done. For example, the TryReceive method returns both an object and a conditional report of success or failure. According to the rule of thumb, when the channel has no more data, it should return null for the received message. Also, it should report a conditional result of success (true, in this case) for the attempt to receive a message. Next time: Body is a Stream Read More...
  • Always Begin with Accept

    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...
  • Live from TechEd Day 2

    I gave a chalk talk on channel development in the afternoon yesterday. I did a huge experiment for the second-half of the talk, which was to write a custom channel from scratch for the audience. That's the kind of theater that you can pull off in a chalk talk but not a regular breakout session. I started with a completely empty Visual Studio environment, wrote a web service, explained why the web service call crashed due to a protocol issue, and then fixed the crash by writing a custom channel. We had 46 people in the audience at the start. The capacity of the chalk talk theaters is only 32 people, but we secured about a dozen extra chairs from the lounges and people stood along the back. Capacity was an issue for several of the chalk talks yesterday. I saw one chalk talk for BizTalk that had crammed almost 60 people into the room. If you're in the audience, it starts getting quite warm after a while. The breakout session rooms are quite spacious on the other hand so I haven't seen any problems there. The Orlando venue has a tremendous capacity and a generally good layout. The only other difficulty was that the standard equipment was a non-adjustable over-ear headset microphone. In addition to making you look like a cross between a call-center worker and a pop star, that type of mic is pretty uncomfortable to wear for an hour and picks up a lot of extra noise if you move around while talking. I tried a half-dozen ways of putting the headset on to fix the issues before the AV guy offered a standard lapel microphone. They had one sitting in the AV case in the room. I don't know why they didn't make the proper equipment available from the start. I promised at the end of the talk that I'd post some resources. Ed Pinto and Kenny Wolf are giving a talk "Architecture of Microsoft Windows Communication Foundation and Common Extensibility Points" on Thursday at 4:30 PM. Steve Maine is giving the buzzword titled talk "Microsoft Windows Communication Foundation Syndication, AJAX and REST Services in Web 2.0 with .NET Framework 3.5" on Friday at 1 PM. There are six samples that I particularly recommend for channel developers. Chunking channel HttpCookieSession channel UDP transport WSE transport UDP activation Config code generator Finally, here is the code that was written during the talk. The scenario was based on an HTTP problem I described back in August . using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.ServiceModel.Channels; Read More...
  • Custom Channel Development

    I'll be giving another talk on channel development for WCF this year at TechEd. Due to the selection of sessions, there's really only one good lead-in talk and it's currently scheduled for later in the week. That means that I'll be spending more time on background material than I normally would. However, if you have any questions about channel development that you'd like to see covered, submit them between now and May 18th. Read More...
  • Writing Channel Manager Essentials

    Once you've obtained a channel manager from the binding element, you have the first object that is usable for network communication. Although the two kinds of channel managers, channel factories and channel listeners, share many of the same methods, the use of those methods tends to be quite a bit different. I'm going through just the client-side channel factory in the list, but I'll point out some bits of information that differ between channel factories and channel listeners. To get a minimally working channel factory for a custom channel, you need to think about what you're going to do in five particular methods. The holdover from binding elements to channel managers is GetProperty. The implementation of GetProperty should at a minimum return a response for every interface that you had support for on the binding element. The return value itself should be exactly the same as well, for the values that would have been returned at the moment you created the channel factory. Future changes to the binding element settings should never change the values returned by the channel factory. Open is a hook to let you perform some work prior to making the first service call. This is your chance to do any preconnection work, like looking up credentials, that you want to have costed during startup rather than taking time during a service call. When programming against a service with a client proxy, opening the proxy is an optional step. However, even if the user doesn't open the proxy, your channel factory and channel will get opened prior to the first call taking place. Close is the hook to let you clean up any state left behind that takes time to get rid of, such as open network connections. There is a different meaning for Close between channel factories and channel listeners. Closing a channel factory is supposed to similarly close all of the channels created from that factory. Closing a channel listener doesn't touch the existing channels. Therefore, you're going to have to structure your state differently between the channel factory and channel listener. For the channel listener, you are essentially forced to push more state into the channels so that they can survive the destruction of their channel listener. Abort is a similar idea to Close, but is a part of the ungraceful shutdown process. Rather than nicely cleaning up the state, you are expected to take care of the state problem by blowing it away with abandon. Abort should never do anything with the network or Read More...
  • Writing Binding Element Essentials

    We're back to the channel development series for another pair of days. When I left off, I promised to talk a bit about writing binding elements and channel managers. Today's article is about writing binding elements and tomorrow's article is about writing channel managers. These articles expand on the checklist items for the steps you have to take while writing a custom channel. To keep things simple, I'm only going to talk about the client-side part of the equation. Where needed, I'll point out that there is an equivalent server-side piece that you need to implement as well. To get a minimally working binding element for a client channel, you need to think about what you're going to do in four particular methods. CanBuildChannelFactory is how you plug into the evaluate step of the channel construction process. This method allows consumers of your channel to validate whether construction is going to succeed without actually performing the build process. You should put your validation in a common place rather than duplicating it between the evaluate and build stages. It will save you a lot of trouble whenever you update your channel. There's a corresponding method for the evaluate stage on the server. BuildChannelFactory is how you plug into the build step of the channel construction process. This method produces the channel manager object used by the next layer of the build process. Primarily what you're doing here is copying settings from the binding element to the channel manager so that future changes to the binding element don't affect existing channels. There's a corresponding method for the build stage on the server. GetProperty is a query interface for dynamically discovering information about the channel. Any properties you don't recognize should be passed to the inner binding element so that channels further down in the stack have a chance to respond. I'll have more details about the interfaces you should implement with GetProperty later. Clone produces an exact copy of the binding element. You should implement Clone by creating a copy constructor and doing all of the work in the constructor. Clone will be called many times during the evaluate and build processes. It is essential that modifying the cloned binding element does not affect the original binding element. Next time: Writing Channel Manager Essentials Read More...
  • Responding to GetProperty

    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...
  • Channel Writing Checklist (Optional)

    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...
  • Channel Writing Checklist (Required)

    This pair of articles marks the checkpoint between the "big picture" introductory segments and the segments where we actually start getting down into the code. The transition is going to be gradual so there's still some philosophy left, particular around the construction of bindings and binding elements. However, the objective of the articles is going to be less about how to think about the system and more about how to think about the code. Here, we get into a checklist of the bare minimum necessary to write a channel. The first few items come from past topics, and you can use the rest as a roadmap of where we're going to go next. Understand why you're writing a channel . Forever more in this series, I'm assuming that you've looked at the other extensibility points and decided that writing a channel is the best way to solve your problem. Identify whether the channel you need is a protocol channel or a transport channel . Identify the channel shapes , one or more, that your channel needs to be able to surface. Write a binding element so that your channel can plug into the build process. The binding element is going to take one of the supported channel shapes and return the factory object that produces channels. Writing a binding is not required as you can always use your binding element in a custom binding. The binding element is also going to hold all of the configurable settings for your channel. Write a client channel factory that can produce instances of your channel for use by client applications. If you have an integration scenario where you're only writing channels for use in a web service, then you can skip this step. For example, if the client is going to be a web browser that doesn't use WCF, then you might not ever have a need to create client channels. Write a service channel listener that can produce instances of your channel for use by service applications. If you have an integration scenario where you're only writing channels for use in a client, then you can skip this step. For example, if you are trying to communicate with an existing mainframe service, then you're only going to produce channels to bridge the connection between WCF and the other system. Write channel instances to cover each of the supported channel shapes. I think it's easier to have separate classes for each channel shape that all use a central communication library. However, you may find it easier to implement multiple channel shapes in a single class. I've put the channel Read More...
  • Channel Development Tour, Part 1

    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...
  • Faking Channel Security

    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...
  • Designing New Faults

    The last piece of this eleven part series on fault messages covers advice for channel authors that need to define their own set of faults. Everything here assumes that you're writing a protocol channel, that you have interesting failure cases that need to be acted on programmatically, and that your protocol does not overlap an existing protocol, such as security, reliable messaging, or transactions. By now, you should either be familiar with all of the classes involved with faults or going back to read the previous articles in the series. Basics of Failure Creating Faults, Part 1 Creating Faults, Part 2 Creating Faults, Part 3 The Most Distinguished Fault A Historical, Awkwardly Named Fault Consuming Faults, Part 1 Consuming Faults, Part 2 Zen Faults Faults and HTTP Let's start with the basic definition of a SOAP fault. It's mandatory to have a fault action, fault code, and fault reason. The fault detail is optional. The fault action is the first round of filtering performed on faults and so you should define an action that is unique to your protocol. Every fault that you create for the protocol should have this same action. Following this rule helps you and everyone else quickly sort out the faults that you need to handle and let everything else go up to the next protocol layer. The fault code should be unique to each expected type of recovery action. For instance, if you have two faults that you need to programmatically handle in a different fashion, then those faults should have different fault codes. If you have two faults that are semantically the same, then those faults should have the same fault code but different fault reasons. Every fault should have its own descriptive fault reason that explains why the fault occurred and what the user should do. Fault reasons are localizable if you're translating your application into multiple languages. The final piece is the fault detail, which you should only provide if you have some extra information that hasn't been covered by one of the previous parts. Your channel should throw exceptions when an error occurs, following the standard rules for exceptions in a CommunicationObject, such as using subtypes of CommunicationException or TimeoutException. The granularity of new exception subtypes should be similar to the granularity of new fault codes. Your channel then needs to override GetProperty<FaultConverter> to provide a converter that translates back and forth between exceptions and fault messages. Your Read More...
  • ListenUriBindingElement

    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...
More Posts Next page »

Copyright © 2006 Microsoft Corporation. All Rights Reserved. | Terms of Use | Privacy Statement | Contact Us