Partilhar via


Polymorphism in WCF

Polymorphism in any OO language is taken as a given – and people would be shouting about it a lot if a language didn’t support it. However, when you’re writing a service interface with WCF you might also want to permit some form of polymorphic behaviour at runtime.

I was working with a customer yesterday and they wanted to be able to extend their system by adding in custom commands. A command might be something like “Print customer record” or “Add customer to ringback queue”. Some of these commands could be executed locally on the client PC, however others might need to be sent up to the server.

On the day I came up with some suggestions but had a nagging doubt that what I’d created wasn’t as great as it could be. Now after a sleep and some more thinking I’ve realised the error of my ways.

The typical Command pattern espoused by the GOF is to have a command object that knows how to execute itself. So in .NET you might dodge up an ICommand interface as follows :-

 public interface ICommand
{
    void Execute();
}

Then you would create subclasses of this command object and be off on your merry way. Note that you could also use the ICommand interface that already exists in the framework – I’m a great one for reusing what’s already available and not re-inventing the wheel. That’s not really appropriate in this instance as I my commands will be remotely executed.

Now, what I want to do is have some commands executed on the server – for the sake of argument I’ll call these ‘Remote commands’. So when the Execute() method is called, what I actually want to call is a WCF service (and pass up something representing the command to the server). To do that I need to be able to pass up an arbitrary collection of arguments. I could use a dictionary but a discrete class feels better :-

 /// <summary>
/// The command arguments class allows arbitrary commands to be executed
/// </summary>
[DataContract]
public class CommandArguments
{
}

And then I might need a derived class for adding a customer to a ringback queue…

 [DataContract]
public class CustomerRingbackArguments : CommandArguments
{
    /// <summary>
    /// The ID of the customer we'll ring back
    /// </summary>
    [DataMember]
    public int CustomerId { get; set; }

    /// <summary>
    /// The duration until we call them back
    /// </summary>
    [DataMember]
    public TimeSpan RingbackWhen { get; set; }

    /// <summary>
    /// The reason for the call
    /// </summary>
    [DataMember]
    public string Reason { get; set; }
}

So far so good. Now I need a service that I can call and pass these command arguments to…

 /// <summary>
/// This service executes commands
/// </summary>
[ServiceContract]
public interface ICommandService
{
    /// <summary>
    /// Execute the command associated with the passed arguments
    /// </summary>
    /// <param name="arguments">Arguments to be used by the command when executed</param>
    [OperationContract]
    void Execute(CommandArguments arguments);
}

If I were then to code up the service and try to use it I would not be able to pass up an instance of my CustomerRingbackArguments class as WCF doesn’t know about the type. Typically in this case you would attribute up the service as shown below…

 [ServiceContract]
[ServiceKnownType(typeof(CommandArguments))]
public interface ICommandService

The problem here though is that for every new CommandArguments derived class I would need to update this service contract. With a couple of command argument derived classes then that wouldn’t be too much of an issue, but what if I were to have 20 or 200 different command argument classes? That would start to make my interface look pretty awful. There is a better way – and one I only noticed today.

The ServiceKnownType attribute can be used to indirectly specify which types are used by the service contract. So, rather than attributing up your code you can define a static method (even on another class) which returns all types that the service interface should use in (de)serialisation.

To use it just choose another overload of the ServiceKnownType attribute :-

 [ServiceContract]
[ServiceKnownType("GetKnownTypes", typeof(CommandServiceHelper))]
public interface ICommandService

Now when WCF is looking for types it will call the static method GetKnownTypes on my CommandServiceHelper class. This method is defined as follows :-

 public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)

All you need to do here is round up all of your CommandArguments derived classes and you’re away! Now you will also need some mechanism to determine just what happens on the server when you get a given CommandArguments derived class sent up to the server, but that’s typically going to be a simple type based lookup mechanism (aka dictionary). I’ll leave that up to you to sort out.

It just goes to prove yet again that old adage – every problem in computing can be solved by another level of indirection.

Comments

  • Anonymous
    July 02, 2010
    very good. Was looking for something like that.