Overview
I'm currently writing a service that needs to provide long-lived callback behaviour to a large number of clients. In this case, the WCF session semantics are not appropriate and so I can't use the ServiceContractAttribute's CallbackContract property.
Why not sessions?
In my scenario, WCF sessions are unwarranted because:
- WCF sessions correlate a group of messages, however I only want to group a single pair
- WCF sessions provide ordered delivery, however this is not needed
- WCFsessions are explicitly initiated and terminated by the calling application
- in this case, the session is initiated by a request from the client,
- but the session is terminated once the return message is sent from the server
- WCFsessions change the instancing behaviour which is not needed in this case
Additionally, the CallbackContract should allow one-way operations only, however the design suggested below also allows for request-response message patterns, although only one-way messaging is described.
This is actually an example of a more general scenario where a client is created at runtime.
Solution
This solution defines a new class that exposes the functionality of the service contract, similar to a generated proxy. I'm showing the steps here because it aids the reader in the understanding of the WCF framework.
In this case, a known WCF service contract is defined in the application, AnyServiceContract. A new class should be defined as follows:
public class AnyClient : ClientBase<AnyServiceContract>
{
public AnyClient(EndpointAddress endpoint) :
base(GetBinding(endpoint), endpoint)
{
}
private static Binding GetBinding(EndpointAddress endpoint)
{
if (endpoint.Uri.Scheme.Equals(Uri.UriSchemeHttp)) return new BasicHttpBinding();
if (endpoint.Uri.Scheme.Equals(Uri.UriSchemeHttps)) return new BasicHttpBinding();
if (endpoint.Uri.Scheme.Equals(Uri.UriSchemeNetPipe)) return new NetNamedPipeBinding();
if (endpoint.Uri.Scheme.Equals(Uri.UriSchemeNetTcp)) return new NetTcpBinding();
return new BasicHttpBinding();
}
public AResponseMessage AnOperation(ARequestMessage msg)
{
return Channel.AnOperation(msg);
}
}
In this example, the constructor determines the binding to use based on the Uri scheme. The example method calls the method on the protected Channel object which implements AnyServiceContract.
To use the client class, you can just create it and use it directly:
using (AnyClient client = new AnyClient(new EndpointAddress("http://tempuri.org/endpoint")))
{
ARequestMessage request = new ARequestMessage();
...
AResponseMessage response = client.AnOperation(request);
...
client.Close();
}
Typically, you would either take the EndpointAddress from a message header (as used in WS-Addressing) or as part of the message body. In the simple case, you can just use a Uri as shown above.
Caveats
The performance of this system is less than ideal. If AnOperation is one-way , the Dispose method of the client will wait for the AnOperation message to be delivered. In some cases, this may also wait for the operation to complete as well (see the Why is my IsOneWay operation blocking? link below). If this is a One-Way method it will still include the attempt to connect and throw an exception if this fails. Additionally, creating a new binding on each call is inefficient. Thirdly, this solution doesn't allow for a custom binding or for specifying security options.
Implementation
I've used this model to implement an event notification service that notifies subscribers when a certain event occurs. This particular solution doesn't implement the WS-Eventing or WS-Notification standards, which should be seen as a best practice approach. Nevertheless, it supports long-lived, loosely-coupled clients, one-way messages over multiple transports and concurrent connections, meeting the particular needs of my context.
Other resources
After I'd begun my design and implementation, I found the following resources that address similar concerns. Some of these were also helpful to my design:
Versions
- Microsoft .NET Framework 3.5
Metadata
- Categories: .NET, Windows Communication Foundation, Software Development, SOA
- Additional keywords: one-way, WS-Eventing, WS-Notification, WS-Addressing, CallbackContract, WCF
- Technorati Tags: .NET, software development, WCF, Windows Communication Foundation, SOA, Service Oriented Architecture, service design, service contract, architecture, WS-Addressing, WS-Notification, WS-Eventing, one way, CallbackContract