1

I have read a few articles on the net about versioning WCF contracts. Here are a couple:
WCF Versioning Guidelines
MSDN: Versioning Strategies

Now, I kind of understand the basics about contract versioning but all of these articles are (of course) mostly targeted environments where there's one server and many clients and where the clients can be older than the server.

In my case it's the other way around, one client and many servers. This is due to the environment where I have one application server (the client) that can communicate with several workstations, i.e. wcf servers.
The client will always have the latest version and the servers might have an older version.

I've planned to implement a separate service (or just a GetVersion method in the same service) to get the version supported by the server and according to that choose the correct contract in the client and make the real service call.

Now the question is, is there any use of lax versioning in this scenario, or should I go with the strict variant.

Anttu
  • 1,076
  • 1
  • 10
  • 21

1 Answers1

0

So you're doing a 'server push'? i.e. your fixed-IP hardware is behaving as a client, and dynamic IP machines are running ServiceHosts?

I really wish there was a 'smart layer' that one could simply lay in place that would deal with versioning here - but there really is no magic bullet. The IExtensibleObject really is just to maintain data for round-tripping, but if the server only has the old contract, then it will also only have the old implementation, so it will not be able to 'use' this 'extended' information.

There are a couple of practices you could follow. The primary difference is, change version numbers, or dont... in the case of WCF contracts there is no version number as such, but the version is encoded in to the contract namespace/URI.

If you dont change the namespace, then you are basically saying, "I will have one service, that will NEVER break backwards compatibility (well, for X versions)". You must then implement a rigorous development practice to ensure that no methods are modified or removed, only additions can be made. This will prevent the client from sending requests that the server no longer understands.

The other approach is to change WCF contract URI/namespace with each revision of the contract. You 'server' will then have an implementation of EACH version of contract that you want to support. If, for example, you are supporting customers for 3 prior versions, they could be running the latest WCF server, but the WCF client must not be older than 3 versions, or the WCF server WILL not understand the request (because the URI/contract namespace will not exist). This is usually the approach that I choose.

To do this, I have a tiered approach

  1. WCF Contracts This are highly static, only change when absolutely necessary Each new contract receives a new namespace/URI Contracts do NOT inherit from the previous version - doing so would prevent you from deprecating functionality.

  2. WCF service implementation This implemetation, or implementations, is just a SHIM layer - it receives the request and passes it along to appropriate logic layer.

  3. Logic layer/adapters if the request has arrived on the latest version contract, then it is immediately processed. if the request has arrived on a prior version contract, an adapter is located for that version (this can actually happen in the service implementation if you like), and the request is passed to the adapter.

The adapters are responsible from receiving an old request, and adapting it to the namespace of the next newer version. This works in a chaining fashion, so, for example, if a request is received from a v1.0 client, to a v1.3 server

1.0 contract -> 
    1.0 to 1.1 adapter -> 
        1.1 to 1.2 adapter -> 
            1.2 to 1.3 adapter -> 1,3 implementation. (and back if not one-way)

Each adapter has the opportunity to perform prepare a request for processing by the next version. For example, in a 1.1 method, you may have introduced the requirement for a 'request date' to be passed, but you know that you can 'make a best guess', so you add that argument in the 1.0 adapter before passing the request to the 1.1 logic.

Remember that it is still possible to introduce requirements that cannot be 'assumed' or 'defaulted' - these would be breaking contractual changes, and you would only want to do this when absolutely necessary. But because you havent chained your contracts, you can support both methods for a while, then drop the old contract from support, and all its old methods disappear.

Next, you also have the choice to separate your entities into another namespace that may be versioned independently from the logic contracts. Another kettle of fish.

You also need to decide how long you want to support old contracts - the longer you support them, the more complex your 'version handling' logic will get. The nice thing about chaining this logic in an implementation like the one above, is once you have written an adapter layer for a specific version, you dont ever have to revisit it.

Hopefully this has given you something to think about.

Adam
  • 4,159
  • 4
  • 32
  • 53