|
|
Browse by Tags
All Tags » Answers » Channels (RSS)
-
When I create a channel to a service, how do I know when the service is ready to process the data for that channel? A channel doesn't really know what the service is doing. The service might be actively processing the data being sent over the channel. Or, the service might not. There is a constant tension in the system between components that want to push data and components that want to pull data. Components that push data actively work as long as there is data available until a back pressure builds up in the system that resists their ability to push. This back pressure is typically the result of some queue or buffer that has filled up and is no longer able to accept the things being pushed into it. Components that push include several transport and protocol channels, as well as the service dispatcher that pushes messages to the service implementation. Components that pull data remain quiescent even if data is available until there is someone that actually wants to consume some data. Many transport and protocol channels pull messages rather than push. A single implementation may feature both push and pull modes. For example, the TCP channel has a small portion that works in a push mode for connection establishment and transferring some initial data while the application portion of TCP works in a pull mode. Depending on the visibility of these push and pull modes, you might be able to tell from the behavior of a particular protocol what the service is doing. For example, if you're using just TCP, then the initial transmissions needed to open a connection can only be completed once a little bit of pulling has been done on the receiving application side, thus telling you that the service is doing some active processing. On the other hand, if you're using a ReliableMessaging channel or a OneWay channel, then those protocols have a visible running state where they are in push mode. You can't actually tell whether the service is working until you fill up some of the buffers in the protocol stack and start getting push back in the form of rejected messages. That means the service is not working as fast as you're sending data. A queued channel would be an extreme example of push mode. A message queue allows you to push large amounts of data when the service is not even running. Therefore, to know in the general case whether the service is ready to process for you, you need to be able to ask that question to the service rather than to the channel. Next time: Composing Read More...
|
-
How do I add SOAP headers to an outgoing request? There are a few different ways to add headers to a message depending on how you need to control the header content and where you need to insert the header. I like to think of these methods as being split among the application, the proxy, and the protocol. In your application code you can create an OperationContextScope around the request in order to change some of the request properties. Inside an OperationContextScope, you have a valid instance of OperationContext.Current, which allows manipulation of the message headers through the OutgoingMessageHeaders collection. Use of this method deeply bakes control of the headers into the application code. You would have to be responsible for copying the appropriate code wherever it was needed. Now, assume that you want the header to be present whenever you're talking to a particular service and the header value can be determined consistently. Rather than having to put the same code at each call site, you can centralize the code in the proxy or in a protocol. The simplest way to centralize header manipulation in the proxy is to create an instance of the IClientMessageInspector and attach that to the proxy. This gives you a hook for every message going through the proxy to modify the message headers. An instance of IChannel similarly gives you a hook for every message going through the channel stack to modify the message headers. Using the Message Interceptor sample gives you an extensibility point in the binding that is similar in spirit to the extensibility point provided by a message inspector. The primary difference from your perspective of a message inspector and a channel is a matter of timing. A message inspector always runs before any of the protocols in the binding while a channel can be positioned precisely in the protocol stack. In most cases you don't need precise positioning, so you should go with the simpler approach. Next time: Adding Headers to a Call (HTTP Version) 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 have a system that sometimes uses a fast local object and sometimes needs to communicate over a network. I have built a proxy object that wraps the proxy factory for creating typed proxies together with a proxy factory for creating local objects. Are there any downsides to this strategy? Historically, there have been a number of attempts to hide whether objects are local or remote from programmers. These attempts have had varying degrees of success. Ultimately, the sticky issue is that it's difficult to prevent network abstractions from leaking. A leaky abstraction allows the environmental details that the abstraction is supposed to be hiding surface into the calling code. Like a leaky basement, a leaky abstraction can lay in wait for a long time before you realize that it's a problem. Problems with leaky abstractions show up when the abstraction author tries to make the surface layer completely seamless. Programmers love seamless abstractions because it makes their code very simple. However, implementers haven't yet figured out how to make any interesting abstraction be truly seamless. WCF attempts to deal with this issue by defining standard behaviors for channels. These standard behaviors are an escape valve so that when the abstraction leaks, it can leak in a controlled manner. For example, channels allow almost any operation to fail but restrict the exception types that the implementer can use and gives those types particular meanings. Or, channels require the programmer specify timeouts and quotas even when the application would rather trust the other side to behave. Or, and this is the most relevant one to the original question, channels require that the sender and receiver decouple their view of message data. Decoupling the sender and receiver means that there can be no way for the sender to modify the receiver's view of the data after a message is sent. In practical terms, achieving this decoupling requires that the data almost always be copied even when using direct object calls. While you can shortcut a lot of things with local objects, the system can't guarantee the abstraction if you bypass channels. There's not a big speed difference between a channel optimized for local communication and a local object that obeys all of the channel rules. Another way of saying that is that channels are extremely cheap if they don't have underlying network resources. There's currently no channel truly optimized for local communication although the named pipe Read More...
|
-
What are the best practices for building retry logic around network transport failures? Let's define some terms first so that we have a common language for communication. I'll say that "retry logic" is any automatically applied compensation activity that replays the same messages to either the same or a different destination. Also, I'll say that a "network transport failure" is any delivery or communication failure while attempting to transmit an application message or an infrastructure protocol message. With that out of the way, there are two places where you could attempt to handle transport failures. In a layered channel. Use a layered channel when you want the retry logic to be applied to all network calls. A layered channel also allows you to finely control the order of operations by positioning the retry logic channel within the channel stack. Placing the retry logic in a layered channel means that you don't have to deal with it at each application call site. In the application. Use application code to perform the retry logic when a retry decision involves business logic, business rules, or application state. For example, if you encounter an error while sending the third of four related messages, you may need to manipulate application state to reestablish consistency within the system. Placing the retry logic in application code means that you have to make use of it explicitly at each application call site. Regardless of the location, the retry logic for a network transport failure is going to look fairly similar. You will find out about a transport failure because some network operation threw an exception. The exceptions that you should consider handling will either be a subtype of TimeoutException or CommunicationException. Your retry logic needs to decide whether the specific exception is recoverable. That decision depends on both the types of network operations that you’re performing and the types of failures that your application is resilient to. Before attempting to retry an operation that uses the same channel, you first need to check that the channel is still usable. If the channel state is anything except for Opened, then you will be unable to send messages using that channel. The only thing that you can do with a Closed or Faulted channel is to throw it away and create a replacement. Next time: A Call to SSPI Failed Read More...
|
-
I've got a sessionful contract that I want to use with HTTP. How do I get the HTTP transport to produce a sessionful channel shape? The basic design principle of channels is that they produce whatever channel shape is their natural message exchange pattern. For HTTP, the natural message exchange pattern is request-reply. This means that if you want any other channel shape, then you need to apply a layered channel that changes the message exchange pattern. That is the approach regardless of whether you want to change the channel shape to one-way, duplex, or a sessionful channel. There are no built-in HTTP specific additions to create sessionful channels. We have a sample channel that demonstrates creating a session based on HTTP cookies . There are several general-purpose protocol channels that provide sessions, such as security and reliable messaging. However, this entire line of conversation tends to indicate a fundamental flaw in thinking. A session has the semantic meaning of correlating messages together according to some principle of relationship. Sessionful services use the relationship to treat the session of messages as a connected unit. The meaning of that session ought to be a more significant factor than whether some contract has been previously declared to know about sessions. If you are scrounging around to come up with any possible session to get a service working, then something is probably wrong. Next time: XML Support 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...
|
-
What happens to the messages being transmitted and any unprocessed messages when I call Abort? Do those messages get delivered or do they get discarded? Once you call Abort, the state of any of the network resources involved becomes undefined. What happens to any lingering messages is implementation-dependent and subject to a large number of timing issues. For example, you may call Abort on the client but the server is blissfully unaware that anything has happened until it tries to read additional messages past the ones it has queued up. Or, you may call Abort on the client and that termination notice races ahead of any data on the wire. Aborting the connection may cause messages to be discarded that were completely received by the server machine but not yet sent to a channel. You have no way of knowing because your connection is gone. If you need some kind of well-defined behavior, then you should be looking at application protocols, reliable messaging, or transactions to give you a more specific guarantee about what occurs during a failure. Transactions are generally the easiest way to get a very precisely defined failure model, but you may find that a simple application protocol, like resending messages and rejecting duplicates on the server, is good enough to solve your problem. What these methods have in common is that they can carry some state around past the lifetime of that connection you just killed. Next time: What a Binary Encoding Means Read More...
|
-
Can I write a point-to-point router service by setting the Via property for outgoing messages? Like most things, this is going to depend on the specific behavior of the transport channel you're using, but in general the answer is no. The transport channel owns the Via property and it will stomp over whatever you write into the message headers. You do have one opportunity to set the channel's Via, which is during the creation of the channel from the channel factory. After that, the matter is out of your hands. This would imply creating a channel per message or keeping a pool of these channels around to farm out messages if you keep using the same destinations over and over. There is a different story if what you want to route to is the ultimate receiver To address instead of the Via address. You can set the To address on a per-message basis, assuming that the transport channel has implemented the ManualAddressing setting . Next time: Enabling Kerberos in IIS 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...
|
-
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...
|
-
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...
|
-
The ListenUri is a three-part setting on the BindingContext that gives the server-side address of a connection. The ListenUri has a base and a relative address, plus a mode switch. The mode switch controls whether the uri should be used as-is or whether parts of the uri have been left unspecified and need to be automatically generated. A common automatic address generation scenario is picking an unallocated network port. There are only a few places where the ListenUri is actually used. One spot is in the transport, which needs to construct a uri for the remote address. The spot that I'll actually talk about though is the composite duplex channel. The composite duplex client channel uses the ListenUri for the backchannel address. I've already covered the basics of composite duplex and how the ListenUri factors into the backchannel construction process . One of the interesting things about the composite duplex channel is that it has a partial fallback for the ListenUri, described in the article above. The ClientBaseAddress setting on the composite duplex binding element lets you specify a base address if the ListenUri is not provided. However, there's no equivalent ClientRelativeAddress that lets you complete the ListenUri. Therefore, if you use this fallback, then you'll always get some randomized component in your backchannel address. You generally want a randomized address because the backchannel address has to be unique across all of your current composite duplex clients. Having a randomized address doesn't work though when you need to allocate a resource with a particular name for the backchannel. MSMQ is an example where randomized addresses don't work because you need to allocate a queue whose name is tied to the backchannel address. When you're programming against the channel model, working around this situation is not difficult because you own creating the binding context. This means that you have an opportunity to directly set the ListenUri. If you are using an automatically generated proxy client like most people do, then you have no opportunity to set the ListenUri. The proxy takes the configured binding and instantiates a copy, including the binding context, automatically. This is entirely hidden from the proxy client user. There are mechanisms for passing information to the channel construction process, called binding and channel parameters, but there is no binding parameter that corresponds to the ListenUri on the binding context. With no way for Read More...
|
|
|
|