April 14, 2014 § Leave a comment
WCF message headers with OperationContext and with MessageInspector and Custom Service Behavior
In this post we will view some possible options for adding message headers to the messages send from the client to service.
We have a WCF service provided as a Software as a Service (SaaS). People who have an active subscription with our company, are able to invoke methods on our service and retrieve information. To successfully invoke methods and retrieve information the client invoking the method must add a message header named “SubscriptionID“ which contains the subscriptionid of that customer. If the subscriptionid does not match a valid and active subscriptionid, access to the operations are denied.
1. Setup and configuration of the Service
The “WCF.MessageHeaders.Client” is a Console Application used to mimic a client
The “WCF.MessageHeaders.Service” is a WCF Service Application, holding our SaasService
Our service is called SaasService and stands for our saas service that provides certain operations for information to external clients.
Our service interface looks as following:
And our service implementation as following (click to view enlarged):
We have 1 public demo method on our SaasService, namely InvokeMethod() with returns a string (or any kind of information). When invoking the method we check if we can find a header called “SubscriptionID” and an empty namespace (for the demo purpose we used an empty namespace, less hassle). If the message header is not found in the incoming message headers, access is denied. If the SubscriptionID message header is found, it is validated against the subscription store to validate it and if it a valid subscriptionid, the required information is returned to the client.
Getting Message headers at the service side can be found at OperationContext.Current.IncommingMessageHeaders. The method FindHeader allows you to check if the header exists and the method GetHeader allows you to retrieve the header information.
Our web.config looks as following:
Nothing special, we just use a basicHttpBinding and we leave the address unspecified as we will host this service in our local IIS. I’m no fan of hosting services in managed applications, unless it’s really necessary.
To host the service easily in IIS, go to the service project properties, go to tab “Web” and instead of using the Visual Studio Development Server use local IIS Web Server and press the “Create Virtual Directory”
Your service should be available at:
2. Setting up and configuring the client
We simply add a service reference to the service url mentioned above.
This is the code we put at our client console application:
If we run our client console application:
Behaves as intended, as we didn’t add any serial key at the outgoing messages at our client, there is no subscriptionID message header found at the message at service, so the access is denied. If we are a valid customer, we have a subscriptionID which we can pass on to the service, which will grant us access.
The code should look as following:
Basically we start by creating the WCF client proxy, which will invoke the operation. Then we create a new OperationContextScope, based on the proxy’s innerChannel. The new OperationContextScope at the client has to be created, before you can access OperationContext.Current.outgoingMessageHeaders, which we need to add a message header to the outgoing messages. If you do not use the operationcontextscope, the OperationContext will be nothing and an error will occur will you try to invoke OperationContext.Current.outgoingMessageHeaders.
Next we create a MessageHeader of type string with the subscriptionID value passed in the message header. This is the subscriptionID which should grant us access to the SaasService. After that we can invoke messageheader.GetUntypedHeader(string name, string ns) which allows us to get an untyped message header, with a defined message header name and namespace. In our case the name is “SubscriptionID”, which is the name of the messageheader the service looks for. Our namespace in this demo is just empty.
After having created the message header, we can simply add it to the outgoingmessageheaders and invoke the method on the proxy.
The result, which we expect:
All by all, adding message headers to incoming or outgoing messages and validating them is not that difficult. However when we have a service with a few tens or hundreds of operations, we do not want to validate the message header at every operation. The solution for that is using a message inspector and a custom service behavior.
3. Use a messageInspector and add a custom Behaviour to our service to validate all incoming messages
We have a SaasService which will expose a few hundreds of operations, for example.
For our first method we used quite some code, to find the header, get the header and validate the header content if it is a valid subscriptionID.
However if I have to write this exact code 99 times more for the other 99 methods I need to implement, that would be silly. We could put the message header validation code in 1 method and in every operation then call that validation method which does the validation and for example returns a boolean. That would save us from duplicating our validation code, however it still requires us to have 100 methods which call all the same validation method and the operation only executes on the result returned of that validation method.
Another possibility is to add a message inspector, which inspects the incoming message before it is handed off to the service operation. At the message inspecor we inspect the message headers to check for the subscriptionid and do some validation if it is provided. If it is not provided or an incorrect subscriptionid is provided, we return an error that the service consumer does not have access to the service. It will save us from writing any validation code at all at our service. We can simply write operations and assume that if the operation is invoked, the client invoking the operation has valid access. Quite a nice solution if you ask me.
How do we implement this:
1. Create an IDispatchMessageInspector at the service side
We start by creating a class “SaasServiceMessageInspector” which is the class which will inspect each message send to our SaasService, inspecting if the subscriptionid message header is present and validate it.
To create a message inspector at the service side, we need to inherit from “IDispatchMessageInspector” which is an interface provided to create message inspectors at service side. The method we need to implement, in our case, is the AfterReceiveRequest, which gives us access to the message after it has been received.
The implementation (click the enlarge):
The message is being passed in the AfterReceiveRequest method, so we can just use the request.Headers to find if our SubscriptionID header is present and whether a valid subscriptionid is provided. If no subscriptionid or no valid subscriptionid is provided, we return a faultexception to the client notifying them that access to the service is denied.
Instead of validating the subscriptionid’s against a database or any store, we just check if the subscriptionid matches “123-456789-098″. If it does not match this subscriptionid, the client should be denied access to the service, even before any method gets invoked. An ideal scenario to easily test our code in a demo.
Now after we implemented the IDispatchMessageInspector we need to write some code that this IDispatchMessageInspector is linked to our SaasService and that this message inspection happens at service level. Any operation that might get invoked of our service, needs to have the message inspected first by the message inspector.
2. Create an IServiceBehavior and attach the custom behavior by attribute
To attach our new SaasServiceMessageInspector to our SaasService, we need to create a new behavior (like which we define in our web.config for example).
There are multiple behaviors we can extend:
- IServiceBehavior: Applies to the entire service
- IEndpointBehavior: Applies to a specific endpoint
- IContractBehavior: Applies to a specific contract
- IOperationBehavior : Applies to a specific operation
For each channeldispatcher we get each endpointdispatcher and add a SaasServiceMessageInspector to the dispatchruntime message inspectors.
Notice that we also inherit from the Attribute, which makes our SaasServiceMessageInspectorBehavior to be used as an attribute.
Also make sure you have System.ServiceModel.Dispatcher namespace imported for the code above.
We can attach our new behavior SaasServiceMessageInspectorBehavior to our Service as following:
We only attach the custom behavior as as attribute on our service, and the custom behavior is automatically attached to our SaasService and we have a message inspector attached to each endpoint dispatchruntime.
Also notice that our InvokeMethod has no more validation code at all at the method. Only method functionality is added.
Our service solution looks as following:
Our client console application remains the same. The subscriptionID used at our client console currently is:
This is the valid subscriptionID we check for in our message-inspector, so we should be able to invoke the method:
Executing the client console application:
Works as intended. If we change the subscriptionid at our client to an incorrect subscription and try to invoke a service method:
Again working as intended. So we created a custom message inspector and a custom service behavior, which did the message header validation for the entire service, only at 1 single and isolated place.
4. What about using a message inspector and custom behavior at the client to add message headers to the outgoing messages
Now we did this for the service, which is a great solution. But what about the client ? If the client has to invoke a few hundreds or thousands of methods of the SaasService, it has to create an OperationScope, create a message header and attach it to the messageheaders, before invoking the operation. (yes you could create only 1 proxy, attach the message header there and always return that proxy to use for invoking operations). Well it is possible to create the same behavior on the client side. Create a message inspector who adds a message header to the request, instead of checking for it and create a custom behavior to attach to your client proxy.
I will not run into all code by detail again, as it resembles the previous section a lot.
We start by creating our message inspector at the client side (click to view at full size):
Notice that we inherit from the IClientMessageInspector now, and not from the IDispatchMessageInspector! The IDispatch interfaces are for service side, while the IClient interfaces are for the client side.
We override the BeforeSendRequest method, which is invoked before the messages is handed over to the channel which will route the message to the service. In this method we create the message header and attach it to our request.
Next we create a custom behavior, just as in the previous section for the service side. Now we will inherit from IEndpointBehavior and not from IServiceBehavior:
The IServiceBehavior is for the service side, so not applicable for the client. The IEndpointBehavior is ideal as it’s scope is a specific endpoint, which in our case is the endpoint to the SaaSService. We use the ApplyClientBehavior. Notice there is also an ApplyDispatchBehavior, in case you would use this behavior for the service side. So the IEndpointBehavior can be used for aswell the client as for the service.
In the previous section we attached the behavior by Attribute to the service. However for an Endpoint behavior this is not possible, it can only be attached by configuration file. To attach custom behaviors by configuration file, we need to create an extension from BehaviorExtensionElement
You will also need to import the reference System.Configuration. Now that we created the behaviorExtension, we can add this behavior extension in our app.config:
To add our behaviorextension at our app.config, we need to add an <extensions> node under <system.serviceModel> and add a <behaviorExtensions> in which we add our custom behavior extension.
We now create an endpoint behavior, that used our MessageHeaderInspector extension:
Notice that in the behavior we use the “MessageHeaderInspector” which is defined at our behaviorextensions with name “MessageHeaderInspector”.
We now attach this endpointbehavior to our client endpoint:
This way our endpoint is linked to the endpoint behavior “SaasEndpointBehavior”, which is our endpoint behavior using the MessageHeaderInspector, which is our custom code to add a subscriptionid message header to each outgoing message for the endpoint we defined.
Our client console code looks as following:
So we do not add the message header anymore in our code. Our message inspector and custom behavior will take care of this, for every operation we invoke with your proxy on the endpoint defined.
Our solutions looks like this now:
When executing our client console application:
April 10, 2014 § Leave a comment
- Odysseas Pentakalos, Ph.D.
Summary: This article shows how the development of a proof-of-concept can bridge the gap very effectively between how the software product is envisioned during requirements definition and how it is ultimately delivered to the customer. (6 printed pages)
A few years ago, I worked on a multiyear project in which we were tasked with the staged development of a custom-made enterprise application for a large organization. Each stage of the project lasted 8 to 12 months and involved the development of a distinct component of the overall solution. Development of the deliverables of each stage was treated as a separate software-development project in which we went through the entire software-development life cycle (SDLC) in producing the deliverables. Over the years, the customer had settled on its preferred software-development process internally, which resembled the waterfall model [Wikipedia] and which the client wanted us to use. Despite our initial resistance to it, we were ultimately forced to follow it.
The goal of the first stage of development was fairly limited in scope, compared with the goals of later stages of the project. The single deliverable consisted of the development of a simple prototype that would help the customer team illustrate to their end users the goals of the project. Due in part to everyone’s excitement at being involved in a new project and in part to the limited scope of the deliverable, we were able to complete the fully functional deliverable early. The customer was very pleased with the results and developed considerable respect in our abilities, which contributed to our team developing a high-level of confidence.
The next stage involved considerably more functionality. The requirements were not as clear, and the time that was allotted was not much longer than what we had available during the first stage of development (despite the much greater scope of the deliverables in this stage). Of course, with our recently acquired confidence, none of those issues was much cause for concern at the time. After a lot of work, late nights, and stress, we managed to complete development.
Next, we prepared for the meeting with the customer. Given our experience with the first stage of the project, we expected that the customer would be awed with our results and that, after offering considerable amounts of praise, they would return to their office completely satisfied with yet another successful delivery. We expected also that they, in turn, would expect us to deliver a fully functional system that did exactly what we all had originally envisioned. From the beginning of the meeting, however, it quickly became clear that what they had envisioned and what we actually had delivered were considerably different concepts. The situation became increasingly tense, as we came to realize that feature after feature that we had provided totally failed (in their opinion) their expectations.
After that meeting, having barely survived a cancellation of the contract, and before moving on to begin the requirements-definition cycle for the next stage of the project, we jointly decided that for the next stage of development we would provide the customer with a proof-of-concept (POC) system at two checkpoints before the overall project would be due. This would allow both our customer and us to confirm that the solution that we were developing was in-line with their expectations; and, if not, to allow us to get back on track before it was too late.
The decision to incorporate the development of POC systems for the rest of the stages of that project was a considerable factor towards successful completion of the overall project. Through that experience, we learned a number of lessons with regard to the value of a POC system.
· Requirements are not fully understood before the project begins.
· Users know what they want only after they see an initial version of the software.
· Requirements change often during the software-construction process.
· New tools and technologies make implementation strategies unpredictable.
In our experience with the project that was described earlier, the development of a POC system provided a cure for three of these issues. First of all, by developing a POC for the customer, we were forced to understand fully the requirements early on. The understanding was much deeper than what one normally receives at the early stages of a new project by simply reading through the requirements, or while incorporating them into the architecture of the system.
The failure that we experienced on that project after the second stage of development was in part due to the second issue that was listed previously. The users were disappointed with our delivery, not only because we misinterpreted the requirements, but also because they did not really know what they wanted until they had seen the deliverable—which, unfortunately, was not what they had in mind. After the customer got a chance to review the POC—which we provided them in the later stages of the project—they got a better idea of what they wanted the final deliverable to look and behave like. Having the POC system also gave us the opportunity to communicate to the user the look and feel of the final product much more vividly than through the use of design documents and design reviews. Seeing the POC allowed them, on the one hand, to adjust their requirements to match exactly what they wanted and, on the other hand, to better define their expectations for the final deliverable. As a result of these adjustments, the customer was much happier with the end result.
At times during the development, we chose to incorporate new technologies; at other times, we were forced to do so. Many of the details that were needed during the design and development of software become known only during the implementation stages [Parnas 1986]. It has been shown consistently that design mistakes that are found early in the software-development life cycle are cheaper to fix than when they are detected later down the road [Eeles 2006]. The POC system provided us with lots of feedback and information of which we were not aware, and allowed us to adjust our design decisions well before the cost of backtracking became too high. The development of a POC system gave us the opportunity to understand and evaluate how to best incorporate those technologies into our design, without having to worry about the complexities of developing the full scope of the system.
As soon as we had a good handle on the capabilities and idiosyncrasies of each new technology (by observing its behavior and operation during the POC development), we were in much better shape to incorporate it into the final product. The risks that we undertook when using the new technologies had been reduced simply due to the fact that, after testing the technology within the scope of the POC system, they were no longer new to our team.
It is important to keep in mind that a POC is just a prototype and does not represent the deliverable. POC systems are usually developed quickly and without a lot of testing, so that they do not make good candidates for early versions of the final deliverable. In cases in which the deliverable includes a user interface, the POC is a façade that illustrates the look and feel of the interface; but there is no functionality behind the façade, much like the houses that are used in Hollywood movie studios. In cases in which the product is an application programming interface (API), the POC illustrates the methods and functionality that the API will provide; but the implementations of the methods are simply stubs that will not perform real work.
When the POC has served its purpose, it is best to throw it away and start with the development of the deliverable. Developers must resist the urge to start development of the final deliverable by enhancing the existing POC. At the same time, the development team must communicate to the customer that the POC is a prototype that looks like the desired system, but, in reality, is just smoke and mirrors. Otherwise, one runs the risk of raising expectations to the point at which the customer will expect the delivery of the rest of the system at the same pace that the prototype was developed.
The features that are implemented as part of the POC should have the key features of the project—especially, the parts of the system that have many unknowns or represent increased risk. At the same time, components of the system that are repetitive implementations of a given concept should be excluded. Implementation of a single instance of a given concept in the POC will provide all of the information that is needed to match a customer’s expectations successfully.
The decision with regard to whether to incorporate one or more POC systems into the schedule also depends on the software-development process that is being used. Despite much criticism—even including some by its own founder [Parnas 1986]—the waterfall model is still quite popular. Because the waterfall model and some of its close relatives do not incorporate iterations that allow for the revision of the requirements and design decisions as development progresses, it is especially important to include the development of a POC system. Other development processes, such as the Spiral [Boehm 1985] or Scrum [Sutherland 2004], prescribe the development of a prototype or early versions of the deliverable that are to be refined over time. The processes can preclude the need for—or the value derived from—the explicit development of a POC system.
As it became very clear to us, when engaging in a new project, it is imperative that the development of one or more POC systems be considered before one settles on the architecture and design of the final deliverable. Development of a POC system provided us with many benefits including, among others, the:
· Very clear understanding of requirements.
· Understanding of the capabilities and limitations of new technologies.
· Ability to assess design decisions early in the process.
· Ability for the customer to visualize early on the look-and-feel of the solution.
· Reduction in the overall risk of project failure.
We had to be careful of the features that we incorporated into our POC system. We had to be very clear to the customer, as well as to the development team, that the result was a POC system and not an early version of the final deliverable. Although the use of a POC provided benefits, we had to be careful about how we incorporated it into the existing software-development process.
· What software-development process are you using? How does the possibility of a POC system fit in with it?
· What is the nature of the POC system for the project at hand? Are you developing an application with a user interface, an API that will be used by third-party developers, or a product that is defined by your marketing team?
· What key features must go into the POC? What features can safely be left out? What aspects of the design must be evaluated and tested, to ensure that the correct decisions have been made?
· What new technologies are being incorporated into your project? How can they be used in the POC system?
· [Boehm, 1985] Boehm, Barry W. “A Spiral Model of Software Development and Enhancement.” Proceedings of an International Workshop on Software Process and Software Environments, Coto de Caza, Trabuco Canyon, CA. March 27-29, 1985.
· [DeGrace, et al. 1990] DeGrace, Peter, and Leslie Hulet Stahl. Wicked Problems, Righteous Solutions: A Catalogue of Modern Software Engineering Paradigms. Englewood Cliffs, NJ: Yourdon Press, 1990.
· [Eeles 2006] Eeles, Peter. “The Process of Software Architecting.” developerWorks. April 15, 2006.
· [Parnas 1986] Parnas, David L., and Paul C. Clements. “A Rational Design Process: How and Why to Fake It.”IEEE Transactions on Software Engineering. February 1986.
· [Sutherland 2004] Sutherland, Jeff. “Agile Development: Lessons Learned from the First Scrum.” Cutter Agile Project Management Advisory Service: Executive Update, 2004, 5(20): pp. 1-4.
· [Wikipedia] Various. “Waterfall model.” Wikipedia, the Free Encyclopedia. December 26, 2007.
Proof-of-concept—A short and/or incomplete realization of a certain method or idea to demonstrate its feasibility, or a demonstration in principle whose purpose is to verify that some concept or theory is probably capable of exploitation in a useful manner [Wikipedia].
Software-development process—A structure that is imposed on the development of a software product [Wikipedia].