Category Archives: Indigo

Posts related to Indigo and Web Services

Building a "Composite" Transport

I’ve often written about how to write custom channels; transports in particular. In all of the examples I’ve given, the same transport is used for both sending and receiving messages (i.e. HTTP out, HTTP in). This parallelism fails in certain scenarios. For example, WS-Discovery defines a pattern where you send out a UDP Multicast probe (a broadcast request to find a peer), and expect (one or more) HTTP unicast responses back.

Constructing a binding for this scenario requires three pieces:

  1. An outgoing transport
  2. An incoming transport
  3. A correlation mechanism to tie the request to the response

For the transports, you need a BindingElement that returns the outgoing transport from BuildChannelFactory and the incoming transport from BuildChannelListener. One way of doing this is with a CompositeTransportBindingElement. A CompositeTransportBindingElement uses two bindings to build its runtime components. For example, you can pass in a binding that consists of OneWayBindingElement + HttpTransportBindingElement. Or one that contains UdpBindingElement.

For correlation, if you add CompositeDuplexBindingElement to the stack, you can configure a ClientBaseAddress and Service Model will provide correlation using WS-Addressing. You could also provide correlation yourself (which is actually a good topic for later this week :))

The relevant pieces of CompositeTransportBindingElement (posted here) are:

class CompositeTransportBindingElement
        : TransportBindingElement
{
    Binding channelBinding;
    Binding listenerBinding;

    public CompositeTransportBindingElement(
        Binding channelBinding,
        Binding listenerBinding)
    {
        this.channelBinding = channelBinding;
        this.listenerBinding = listenerBinding;
    }

    public override IChannelFactory<TChannel>
             BuildChannelFactory<TChannel>(BindingContext context)
    {
        return channelBinding.BuildChannelFactory<TChannel>(
            context.BindingParameters);
    }

    public override IChannelListener<TChannel>
            BuildChannelListener<TChannel>(BindingContext context)
    {
        return listenerBinding.BuildChannelListener<TChannel>(
            context.ListenUriBaseAddress,
            context.ListenUriRelativeAddress,
            context.ListenUriMode,
            context.BindingParameters);
    }
}

Using Overloaded Operations in your ServiceContract

A common programming paradigm with objects is the use of overloaded methods. That is, multiple methods with the same name, but different parameters. In reality though, this paradigm is syntactic sugar on top of a compiler that is generating different fully-qualified names.

It may be that you’ve done your service-oriented scrub and decided you want to expose two overloaded methods. From a service-orientation perspective, the compiler isn’t adding extra qualifications to differentiate the methods. Our default action generation is based on the operation name, which defaults to the name of your method. As such, in order for a client (and our dispatcher) to distinguish between multiple overloaded methods, you need to provide them with unique names. For example:

[ServiceContract]
interface ICalculator
{

[OperationContract(Name= "Add_Int")]
int Add(int x, int y);

[OperationContract(Name= "Add_Long")]
long Add(long x, long y);

}

IReplyChannel and "null" replies

I mentioned in an earlier post how the Service Model Runtime normalizes different channel shapes based on the requirements of your OperationContract. One of the adaptations the Service Model Runtime provides is the ability to use one-way methods over IRequestChannel and IReplyChannel.

For example, let’s say you have method such as:

[OperationContract(IsOneWay=true]
void SendUpdate(string update);

If you want to expose this method over BasicHttpBinding, how does that work? HTTP is fundamentally request-reply based, and as such offers up only IRequestChannel and IReplyChannel.

To address this scenario, part of the model for request-reply is a paradigm whereby a channel can optionally support “null” responses. This is exposed through the programming model by calling IRequestContext.[Begin]Reply(null). As an additional convenience, if you call IRequestContext.Close() without having sent a reply we will call Reply(null) on your behalf.

HTTP signals a “null” response on the wire by sending a “202 Accepted” with no entity body. Note that for interop purposes we are lax on the client and allow any 200-level response without an entity body to signal null response. TCP/Pipes send a .Net Framing ACK with no entity body. A message-level protocol for request reply can designate a particular schema/action for an “ACK Message” to signal a null response.

On the client you should check for a null return value from IRequestChannel.SendRequest(). For example:

Message reply = requestChannel.SendRequest(request);
if (reply == null)
{
    Console.WriteLine("Called a one-way method.");
}
else
{
    Console.WriteLine("Called a two-way method.");
}

ServiceModel, as well as our forthcoming OneWayBindingElement leverage the “null” response in order to achieve mapping request-response message exchanges to one-way.

Building a "client-side" Listener

I wrote earlier about how to write a Service that listens on any free port. If you are programming at the Channel/Binding layer directly, the easiest way to autogenerate a ListenUri is to call the following method on your Binding:

public IChannelListener<TChannel> BuildChannelListener<TChannel>(params object[] parameters)

For example: myListener = myBinding.BuildChannelListener<IInputChannel>();

The base class will expand this call out to create a Listener using the scheme from the binding, the hostname of the machine, and ListenUriMode.Unique to generate the rest of the ListenUri:

UriBuilder listenUriBuilder = new UriBuilder(this.Scheme, machineName);

return this.BuildChannelListener<TChannel>(listenUriBuilder.Uri, string.Empty, ListenUriMode.Unique, parameters);

Exposing Capabilities on your Binding

Bindings represent a wide variety of functionality. Everything from different transports, to different security mechanisms, delivery mechanisms, transactions, and custom protocols. Nonetheless, there are times where you want to make a decision based on a binding’s capabilities.

For example: “Does this binding support ordered delivery?”
Or: “Does this binding support both client and server authentication?”

WCF has a polymorphic way of making such inquiries of a Binding, though there are a few subtleties involved.

The first pivot point is to decide whether the capability is a property of the actual Binding, or a property exposed by the stack of Binding Elements. For example, supporting client authentication is a property of the underlying stack. It can be added at different layers (e.g. transport, WS-Security, etc), and can even be removed by some layers. These capabilities are accessed though a method on the Binding:

T GetProperty<T>()

As in:

ISecurityCapabilities s = binding.GetProperty<ISecurityCapabilities>();

GetProperty<T> simply constructs a Binding Context representing the stack of Binding Elements, and queries them through:

T GetProperty<T>(BindingContext context)

Each individual Binding Element can handle the inquiry itself, delegate the inquiry, or a combination of the two. GetProperty is also supported by the runtime objects (IChannelFactory, IChannelListener, IChannel, etc).

Conversely, if a Binding claims to support Basic Profile 1.0, that is a claim about a particular coordination and configuration of binding elements. Therefore, this is not a feature to expose through T GetProperty<T>(). The Binding should instead implement the capability directly. For example:

public class MyBasicProfileBinding : IBasicProfile10Binding

Where IBasicProfile10Binding is an agreed upon interface. It is queried as “if (binding is IBasicProfile10Binding)

Lastly, there are a handful of cases where a particular property is applicable to all bindings. In that case, we use the traditional approach of a strongly typed property on our base class. For example:

public abstract string Scheme { get; }

To re-cap: for polymorphic properties, use GetProperty<T>. For capabilities of the binding element stack, and interface implementation for composite capabilities provided by the concrete binding.

Configuration Http Proxies in WCF

When using Http, proxy configuration madness is a fact of life. If misconfigured, you can wind up trying to decipher obtuse 502 (Bad Gateway) and 504 (Gateway Timeout) errors.

Fortunately there are a number of binding settings available in WCF to control your Http proxy usage. These settings are available directly on BasicHttpBinding and WsHttpBinding (as well as on HttpTransportBindingElement when you are using a CustomBinding).

  • public bool UseDefaultWebProxy (default == true): if set to true, will use the global value HttpWebRequest.DefaultProxy as your proxy. HttpWebRequest.DefaultProxy is controllable through System.Net config, and defaults to using the system proxy settings (i.e. when you see in your Internet Explorer properties).
  • public Uri ProxyAddress (default == null): If you want to specify a proxy directly you can set a proxy Uri directly here. To ensure no proxy is used you can specify “null” here. In both cases be sure to set UseDefaultWebProxy = false as well.
  • public bool BypassProxyOnLocal (default == false): used in conjunction with ProxyAddress for when you specify a proxy. If you want “local” addresses (i.e. addresses on your intranet) to connect directly without using the proxy, set this value to true.
  • public HttpProxyCredentialType HttpTransportSecurity.ProxyCredentialType (default == None): Specifies the authentication mode used with your Http proxy. For custom bindings the equivalent setting is public AuthenticationSchemes ProxyAuthenticationScheme (default == Anonymous) on HttpTransportBindingElement. For proxy authentication we will obtain the credential using the shared WCF provisioning framework (SecurityTokenProvider, etc). We simply pass in the proxy address (rather than the target address) for acquiring these credentials.

One last note about proxies: if you see a 502 or a 504 error returned to your client, then your client is using a proxy server. If this was not your intention, you can disable the server by setting UseDefaultWebProxy to false, and using the default ProxyAddress of null. The other possibility is that your proxy is misconfigured and you can use the above settings to rectify that situation 🙂

Channel Authors unite!

Hot off the presses is a new resource for channel authors: the WCF Custom Channel Resources page at wcf.netfx3.com. This is a great portal for samples, documentation, and all things Channel-related.

The samples page contains updated versions of our PDC demos (WSE 3.0 TCP Interop and Chunking Channel) as well as new helpers for testing and generating config for your channels. Check it out!

UPDATE (06/21/06, 3:50P): updated links to point to our new community website

Demystifying HostNameComparisonMode: Wildcards, and URI Matching

Today I was asked “what is StrongWildcard and WeakWildcard, and which one should I use?”. The piece of object model that my co-worker is asking about is:

public enum HostNameComparisonMode
{

StrongWildcard = 0,
Exact = 1,
WeakWildcard = 2,

}

Most bindings have a HostNameComparisonMode property on them. This property is used for service-side endpoints (IChannelListener), in conjunction with the ListenUri of that endpoint. The values are semantics similar to + and * for http.sys registrations. “Wildcard” vs. “Exact” refers to how we match the authority (hostname+port) piece of an incoming Uri. For “Wildcard”, anything matches. For “Exact”, we perform a case-insensitive string comparison to determine equality.

“Strong” vs. “Weak” has to do with the relative priorities of endpoints. We use three longest-prefix-match tables, one each for StrongWildcard, Exact, and WeakWildcard. When a Message comes into the system, we first try to match the Uri against our Strong table (which uses a wildcard comparison on hostname+port). If nothing matches, we try the Exact table (using a case-insensitive exact comparison on hostname+port). Lastly, if there was no match on Strong or Exact, we check the Weak table (again using a wildcard match for hostname+port).

For example, let’s say you have the following endpoints registered on your machine:

  1. (http://foo.com/a/b/c/, StrongWildcard)
  2. (http://foo.com/a/b/, Exact)
  3. (http://bar.com/, Exact)
  4. (http://foo.com/a/, WeakWildcard)

A request coming in for http://foo.com/a/b/c/d/ will match (1).

A request for http://foo.com/a/b/ will match (2) since the strong comparison fails (/a/b/c/ is not a prefix of /a/b/).

A request for http://foo.com/a/d/ will match (4). Even though “/” is a prefix match of “/a/d/” for (3), the hostnames differ and so the Exact match will fail.

Lastly, a request for http://bar.com/a/b/ will match (3). (2) is a prefix match but the hostnames differ, and (3) takes precedence over (4) in priority order.

Hopfully this helps demystify our endpoint URI matching process!

Creating a Service on "any free port"

By default, when creating a ServiceHost we require you to specify a base address (e.g. “http://kennyw.com/myService/”). This is because your clients needs to know where to send messages to. Sometimes you have a situation where you don’t need to know the exact address up front (let’s say you are using WS-Discovery or some other registry-based lookup). In that case, you want to indicate to the transport to “use any free port” (or “port 0” in sockets-speak). Fortunately, Indigo has this functionality baked into our addressing parameters.

To signal you want this behavior, set ServiceEndpoint.ListenUriMode to ListenUriMode.Unique (the default is ListenUriMode.Explicit). At build time this will propagate to BindingContext.ListenUriMode, which will then cause the Transport to “unique-ify” the ListenUriBaseAddress.

For exclusive TCP (where the process is directly listening on a socket) we will bind to a uniquely available port#. For shared TCP, Pipes, and HTTP we will append a GUID to the base address which will uniquely identify this endpoint.