WCF/SOA – Why should I create parameter objects for simple requests

soawcf

Our company is starting a fairly large SOA initiative. We're doing a lot of stuff right: there's good communication; money for tools where appropriate; and we have brought on some good expertise to help us with the transition.

We're trying to develop standards that we can follow as a group, and one of the proposed standards is bothering me quite a bit:

We have standardized on the pattern where every operation takes a request object and returns a response object.

I realize that this is more or less a standard approach for a lot of folks, but I am asking why should I bother? (I'm not so good with received wisdom, I need some why).

Most of the services that I will be providing are simple organizational metadata retrieval. For example, find the security policy for a particular user. This needs a user id and nothing else. The standard tells me that I should wrap this request in an object and wrap the returned policy in a response object.

My unease is amplified by a look at the WSDL that is generated from our contracts. WCF generates request and response messages automatically and wraps even the request/response object.

I fully understand that if you're making a complex request then a complex input object is warranted. That's what you would do even if services wren't involved.

My question is why should I automatically wrap requests and responses when:

  • It makes simple services less expressive
  • You would do it anyway for a complex service
  • WCF creates a request/response message anyway

I have found the following arguments in favor of this approach:

It supports versioning by allowing optional parameters to be slipped into the request object.

Back in the day, I did a fair bit of COM, and I would consider this almost an anti-pattern for versioning. For some things, I suppose it would help, but I expect that where it would help, you already have a parameter object anyway.

It allows common data and behavior to be isolated to a base class

This one carries some weight with me.

It steers people away from an RPC style behavior and towards a messaging behavior

I've read this on Microsoft's site and heard it from our guru, but I still don't have a clear idea what they mean or why it's valuable. Is it that natural looking interfaces make people tend to forget that they are calling a remote service?

I am looking at refactoring the signatures of perhaps 300 methods, so this is a non-trivial amount of pain. I'm a huge fan of consistency in implementations, so I'm willing to take on the pain, it will just help to know that it will all be worth it in the end.

Best Answer

I think versioning is probably the best argument. When you have an existing operation contract like

int GetPersons(int countryId);

that you want to enhance, e.g. by another filter later on

int GetPersons(int countryId, int age);

You would have to write a new operation contract and with a new name since it has to be unique. Or you would keep the name and publish a new v2 of your service with the old v1 still being around for backwards compatibility.

If you wrap the parameter into an object you can always extend it with default/optional parameters and all your existing clients will be unaffected when you reuse the same operation contract.

However I would also urge to name your objects appropriately. Even if it just wraps an int, if you start with IntMessage or something similar you're not doing yourself a favor extending it. You'd have to name it e.g. PersonFilter right from the start which means you have to think a little about what this service call should expect as parameter semantically and therefore what it's supposed to do. Maybe (and that's a very vague maybe) that's going to help in developing the right services and maintain a decent sized API.

It allows common data and behavior to be isolated to a base class

That's something to be cautious with. Inheritance and data contracts don't go that well together. It does work, but you'll have to specify all known subtypes of the contract that could go over the wire, otherwise the data contract serializer fails complaining about unknown types.

But what you could do (but still probably shouldn't, I'm still undecided on this) is reuse the same messages among different services. If you put the data contracts in a separate dll you can share that between client and service and you don't need to convert between types when you call different services that expect basically the same message. E.g. you create a PersonFilter and submit that to one service to get a filter list of persons and then to another service and have the same objects on the client. I can't find a good real-world example for that though and the danger is always that an extension to the data-contracts is not general enough for all services that use this contract.

Overall, apart from versioning, I can't really find the killer reason for doing it that way either.