8

I am using WCF for data services only (ie internal to the application and very lean with no session state etc) to keep our web application scalable.

We need to provide some common properties for every service call that we are currently passing in all the time. Having single request objects for every call is not ideal as beyond these common properties, the rest are very varied and change quite frequently during development.

At the moment I'm considering using custom headers and the clientmessageinspector to do to set the values. Is this the simplest recommended approach for this scenario or is there a better approach?

More detail..

The red points below are where I'm unsure the right approach (or how to go about it).

enter image description here

What's being sent

The data being sent is simple set of ids (3 or 4 for userid, clientid etc) - all these ids have an impact on security and on performance (in some cases it determines what database to go to).

We will also be extending this to have more complex permissions - not needed for the windows workers.

The caller will be either a web application where these come off a session object, or a windows service worker where these are manually populated.

The Current Thinking

Ideally, getinstance on the caller's workflow would either populate these properties automatically with the session object or more manually with the windows service calls (different constructors?).

We would then ensure that these parameters are always available without any thought or without constant references throughout the code to construct the contract on each function that calls it. We currently have a lot of service calls (due to scale/complexity of app, not due to bad engineering :)), so as this extends for complex permissions it is becoming a bit difficult to enforce rules in a self-documenting way.

Conceptually, session is where you'd take care of this in the app, but the services are really just a data access layer (with view mapping, pageing and last call security from repository calls) so we don't need that sort of repitition or complexity, just the key identitiy & permission fields to include in queries.

The Problem

This feels very much like something we should be doing with headers on the calls as we always need these fields, but I'm a little unsure of where the set and get should sit in the lifecycle of the endpoint and the client interface. I'm also happy to be wrong about that.

Gats
  • 3,452
  • 19
  • 20
  • 1
    What you seem to be considering is called the Canonical Model Message Scheme http://soapatterns.org/patterns/canonical_schema and is a robust approach. – Martin Spamer Jan 24 '13 at 17:17
  • Hi Martin, That is the pattern suggested by @Slugster below, but we really don't want the layer of abstraction that comes with contracts on every call. Most of our requests require simple parameters as our services are internal, we don't need versioning etc. Parameters are more self documenting unless doing complex search style operations in which case we use a contract. – Gats Jan 28 '13 at 03:39

3 Answers3

3

In my experience using message insprectors can be quite tricky to initially set up and configure, and in my research there was no site that covered everything, I had to pick snippets from several different places and piece it all together.

You need to question what you are putting in the headers. Is it information that needs to be available to the method being called? If so then putting it in the headers is the wrong option, as each method will need to parse the info back out.

The sort of info that is ideal for this is custom authentication and/or user specific metadata related to the WCF call. In my case I had a WCF call initiated by an automated service which was relayed to further WCF end points, this was an ideal scenario to use message inspectors as I was able to add metadata to the headers at the relay points for consumption by the subsequent end point.

If youy are simply looking to package up some data that is common to each call, then I would include create a base data object that has the appropriate properties and then just extend that for the more specialised calls (the end point can ensure that common data is either present, or assume some default values if it isn't). For common data required by each end point using message inspectors is overkill and potentially not viable.

slugster
  • 49,403
  • 14
  • 95
  • 145
  • So the data would need to be parsed on each call which is a bit clunk right? The problem I have with a common data contract is that we have hundreds of calls and I don't want hundreds of message contracts or contracts with redundant fields. Our wcf layer is really a form of data access so lean and easy to read is essential. I had hoped to have the poperties "just there" and the service calls lean with the "extra" properties. – Gats Jan 19 '13 at 08:45
  • The other thing giving me uncertainty is that the data we're talking about is very user metadata. I was hoping to have this data populated by the workflow layer (that calls the service) at "getinstance" point so it is a bit of set and forget. With a common contract, it still needs to be populated at every call to be passed in. I also have both windows services and a website calling them, so slightly different concerns could be resolved with a change to the getinstance call. – Gats Jan 19 '13 at 08:50
  • 2
    @Gats How much of that user specific data can be stored statically in the database (so doesn't need to be passed every call - all you have to pass is an identifier)? Quite simply, if the *endpoint* is going to be dealing with the information, it can go in the headers. If the called *method* is going to deal with it then it belongs in the contract data objects (hence my comment to have them in a base object that all other data objects derive from). – slugster Jan 19 '13 at 11:43
  • But maybe a better answer for you would be to have session state enabled on the server - you make an initial call to "log in" and create the session, then common stuff can be kept in session on the server until the session ends? This way there is no need for message inspectors and no need to make it part of every call. – slugster Jan 19 '13 at 11:44
  • Thanks again @slugster. I'll clarify some of the reasoning in the question. – Gats Jan 19 '13 at 22:52
  • My objection to having other objects derive from a base contract is the lack of transparency of what the service requries. Beyond the core paramters, we require different params on every call so it would get very ugly and too much work for an internal scenario (perfectly reasonable for external service calls). At the moment the code is lean, fast to work with and very self-documenting, so a contract for ONLY the core properties is not out of the question, but I'm hoping to avoid having to populate it every call. – Gats Jan 19 '13 at 23:25
  • 1
    Have you considered using OperationContext.IncommingMessagePropreties. You can define your own message property and is tied to a particular request at the serviceModel layer. these are faster than headers and do not affect wire format and also these are available at MessageInspector and other layers in the pipeline. – Sajay Jan 24 '13 at 11:04
1

This may be an older approach, but you may easily leverage CallContext from System.Runtime.Remoting.Messaging. The client could use an implementation of IClientMessageInspector to set the call context on operation invocation, and an implementation IMessageInspector on the server to retrieve the shared data from the CallContext.

Capps
  • 182
  • 7
1

I have applied a similar architecture; basicly every client call needs to carry some information regarding which DB to be selected, an identifier etc. And in the server side, these parameters shall be processed automatically and stored in a dictionary.

I have created a generic proxy class to wrap client proxies, in order to add related headers to each service call. Every developer who needs to call a service, used this generic proxy class in their calls.

In the service side, I have implemented a DispatchMessageInspector as an endpoint behavior, where data is extracted from request headers and stored in a dictionary. The dictionary is initialized inside an extension of OperationContext (IExtension<OperationContext>) and is available during the request processing.

Note that the instance context mode of services are PerCall.

daryal
  • 14,643
  • 4
  • 38
  • 54
  • Hi Daryal, You wouldn't have examples of this would you? – Gats Jan 28 '13 at 03:36
  • Marked this as the answer although I would like more concrete examples. – Gats Jan 28 '13 at 04:39
  • 1
    @Gats I can not share the code directly because of company restrictions but the following links may help http://www.codeproject.com/Articles/73506/Summarizing-Client-Side-Asynchronous-Invocations-i and http://blogs.msdn.com/b/zelmalki/archive/2008/12/29/creating-a-wcf-idispatchmessageinspector.aspx and http://www.codeproject.com/Articles/352678/Add-Custom-Message-Header-in-WCF-4-Calls – daryal Jan 28 '13 at 07:44