AJ's blog

March 28, 2015

WCF Policy – Part 11: Famous Last Words

Our policy works. Every aspect – defining the standard, switching it on, publishing the policy assertion, evaluating it for the client proxy, default behavior, and making the information accessible on client and server – contributes to a system where all pieces work together.

To get an overview and TOC, please refer to the initial post

The policy plays well with WCF. The application developer can switch the policy on, and everything else happens automatically (with minor exceptions, e.g. registering the policy importer). If needs be he can access the information similar to other built in information (again, with minor exceptions). This is very close to what’s provided by WCF out of the box.

And what’s more, it builds on standards that are not platform dependent: WSDL, WS-Policy, SOAP. Other platforms offer similar capabilities, for example Metro for the Java world. (This work is actually based on project where cross platform availability was demanded.)

 

On the other hand, we had to do quite a lot to make it work. Question is, when and why would you want to do this?

Having a WCF Policy is certainly nice. Building a WCF Policy however is something that needs to be decided carefully.

Creating policies is certainly not part of the every-day-work of the average developer. Rather it’s part of the foundation laid out by experienced developers or some framework team in the organization. Policies are also usually cross cutting concerns, orthogonal to the business demands, and perhaps optional. And finally the effort is only justifiable for demands occurring regularly.

The biggest obstacle in my opinion is that implementing a WCF Policy requires a familiarity with the internal workings of the WCF that goes beyond what the average developer – including service developers – need and usually have. On the other hand, should you have someone with that skill, then policies might be a means to provide complex demands to other application developers in a seamless and easy-to-use way, and shield them from WCF intricacies.

In other words: Custom WCF Policies may be a rare demand. But at times, and if circumstances allow, they can be very handy.

 

Did I forget something? Oh, yes. You can find the sample application on github

That’s all for now folks,
AJ.NET

March 15, 2015

WCF Policy – Part 10: Addendum: Extending Bindings

Filed under: .NET, .NET Framework, C#, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 4:38 pm

During the last posts we talked a lot about behaviors, but only in passing about bindings.

 

Bindings for policies relying on behaviors.

Our policy was defined in a way that extended the behavior of clients and services. Still we needed a BindingElement for exporting the policy assertion (and we took a shortcut on top of that). However, in order to use BindingElements you need a custom binding (no WsHttpBinding or other). Should you have another binding already in place, you need to change this – which however implies an unnecessarily complicated translation from other bindings to custom bindings. Yaron’s converter might help with this.

 

Policies relying on bindings.

Some demands do not affect the behavior of the service, but the message content on the wire. Examples include custom encodings, compression, or similar requirements. These demands should be realized by bindings instead of behaviors. Unfortunately this requires quite a bit more effort.

Providing a custom binding implementing the demand is probably the simple part. On top of that, one needs to customize the building of the channel. Replacing an existing binding, e.g. the message encoding stage, is shown in WCF Extensibility – Policy Import / Export Extensions. It gets even more complicated if an additional binding needs to be inserted. The SDK sample Custom Message Interceptor shows how this can be accomplished. Carlos explains it a bit more in detail in his posts WCF Extensibility – Channels and WCF Extensibility – Channels (server side).

 

As a personal note…

I cannot see any reason why the above tasks have to be so complicated or why they require so much effort. Specialized bindings, such as WsHttpBinding build internally on binding elements, so there should be a straight forward translation between bindings. Similarly WCF channels are a simple pipeline, which is a pattern that is common enough. Why are the stages nearly set in stone, why does it take so much effort to introduce extensions?

WCF is at times rather complex due to the complexity of the protocols that need to be configured. Adding unnecessarily (I think) to this complexity is just annoying.

Just my 0,02€.

 

That’s all for now folks,
AJ.NET

February 15, 2015

WCF Policy – Part 9: Making the Information Accessible on the Server

Filed under: .NET, .NET Framework, C#, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 3:14 pm

On the client we can access the tracking information. On the server this would also come in handy, e.g. to add additional tracking entries, say for lengthy operations, such as database calls.

Whenever an application developer needs access to the current context during a service call, he does so via OperationContext. And OperationContext provides with its property Extensions exactly the extension point we need – if we can place an object in there, that implements our ITrackingInformation.

Operation extensions are classes implementing IExtension<OperationContext>. Providing a class that implements both, this interface and ITrackingInformation, is a simple exercise: Just deriving from TrackingInformation – the object we used to temporarily maintain the tracking information – and implementing the interface methods trivially is sufficient:

internal class TrackingOperationContextExtension : TrackingInformation, IExtension<OperationContext>
{
    void IExtension<OperationContext>.Attach(OperationContext owner) { }
    void IExtension<OperationContext>.Detach(OperationContext owner) { }
}

Now we need to change our message inspector to maintain the tracking information in an extension, rather than a temporary object. As on the client, due to some foresight, we only need to change one method:

private ITrackingInformation GetTrackingInformation()
{
    var extension = new TrackingOperationContextExtension();
    OperationContext.Current.Extensions.Add(extension); // register extension
    return extension;
}

And that’s it. Now the application developer can get hold of the incoming tracking information and add his own entries, as he likes:

var tracking = OperationContext.Current.Extensions.Find<ITrackingInformation>();
tracking.OutgoingHeaders.TrackingEntries.Add(new TrackingEntry(typeof(TestService).Name, "My tracking information..."));

 

After the first posts addressed the design time aspects, this post concludes the runtime aspects of our policy. The following image shows the related components at runtime:

And this screenshot shows the result generated from a sample application:

 

Our policy implementation is finished at this point, however, there is another post coming, looking at aspects we did not touch.

 

That’s all for now folks,
AJ.NET

January 31, 2015

WCF Policy – Part 8: Making the Information Available on the Client

Filed under: .NET, .NET Framework, C#, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 4:37 pm

Our policy has its default behavior. All the information is collected, it just is not available to the developer yet. So let’s take care of that.

We already have the basics covered, namely we have an interface ITrackingInformation through which the application developer should have access to the information. All we need to do is to build a bridge between message inspectors and the application code.

On the client the application developer uses the generated client proxy class, thus we need to pass in the tracking information to that object. The class derives from ClientBase<TChannel> and thus inherits the property Endpoint of type ServiceEndpoint. This class in turn maintains a collection of endpoint behaviors. With a custom behavior which implements our interface, the developer has the gate to our policy. Going one step further, this behavior can also register a message inspector in IEndpointBehavior.ApplyClientBehavior, which utilizes the information passed in, instead of a temporary object, as we did when we implemented this last time.

The endpoint behavior is actually quite simple:

public class TrackingEndpointBehavior : IEndpointBehavior, ITrackingInformation
{
    public TrackingHeaders IncomingHeaders { get; private set; }
    public TrackingHeaders OutgoingHeaders { get; private set; }
    
    void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new TrackingClientMessageInspector(endpoint, this));
    }
    […]
}

And given the fact that I “kind of had this in mind”, the changes to the message inspector are also minor: We need an addition constructor and member for the information passed in, which is boilerplate enough. Additionally the method to get the tracking information object changes slightly:

private ITrackingInformation GetTrackingInformation()
{
    var tracking = _providedTrackingInformation ?? new TrackingInformation();
    return tracking;
}

The other code worked already against the interface and does not care where the tracking information object came from. I love it when a plan comes together.

There is one thing left: The contract behavior created during code generation is still in place and still registers its own message inspector. This is still necessary in cases where the application developer does not provide the above endpoint behavior, but hurts if he does. Luckily the contract behavior’s ApplyClientBehavior method is called after the endpoint behavior’s method. So all we need to do is to check:

void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
    var endpointBehavior = endpoint.Behaviors.OfType<TrackingEndpointBehavior>().FirstOrDefault();
    if (endpointBehavior == null)
        clientRuntime.MessageInspectors.Add(new TrackingClientMessageInspector(endpoint));
}

And, finally, the application developer can provide the endpoint behavior and use it to pass additional tracking entries in or read the tracking entry collections after the call:

var client = new TestServiceReference.TestServiceClient();
var behavior = new TrackingEndpointBehavior();
behavior.OutgoingHeaders.TrackingEntries.Add(new TrackingEntry("my code", "just for fun"));
client.Endpoint.Behaviors.Add(behavior);

var response = client.Ping(“Ping text”);
var trackingEntries= behavior.IncomingHeaders.TrackingEntries;
[…]

So far for the client, next time, we will look at the server.

 

That’s all for now folks,
AJ.NET

January 24, 2015

WCF Policy – Part 7: Implementing the Default Behavior

Filed under: .NET, .NET Framework, C#, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 3:43 pm

Our policy demands that we read and manipulate the messages going in and out, on client and service. The WCF component designated for this demand is a message inspector, which is available in two flavors, designated by the interface: IClientMessageInspector for the client, and IDispatchMessageInspector for the service. Both interfaces provide two methods; one is called for the incoming message, the other for the outgoing message. The respective runtimes – ClientRuntime und DispatchRuntime – each maintain a collection of respective message inspector instances.

On the client the contract behavior created by our import extension can add the message inspector in IContractBehavior.ApplyClientBehavior, nothing more than a one-liner:

void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
    clientRuntime.MessageInspectors.Add(new TrackingClientMessageInspector(endpoint));
}

On the server, our service behavior can do the same, only it needs to address all eligible endpoints:

void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
    foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
    {
        foreach (EndpointDispatcher ep in cd.Endpoints)
        {
            var inspector = new TrackingDispatchMessageInspector(ep);
            ep.DispatchRuntime.MessageInspectors.Add(inspector);
        }
    }
}

If the application developer calls a service method on the client proxy class, the WCF creates a message object for the resulting SOAP message. It the proceeds to call IClientMessageInspector.BeforeSendRequest on all message inspectors.

In this method our TrackingClientMessageInspector creates an ITrackingInformation object to maintain the information, creates the first tracking entry for sending the message, passes it to your header class, which will later serialize it as SOAP header, and adds it to the collection of headers. Finally it returns the ITrackingInformation object as correlation state:

private ITrackingInformation GetTrackingInformation()
{
    var tracking = new TrackingInformation();
    return tracking;
}

object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
{
    // get headers
    var tracking = GetTrackingInformation();
    
    // add send information
    tracking.OutgoingHeaders.TrackingEntries.Add(new TrackingEntry(_thisClient, "Send Request to " + _calledService));
    
    // tracking entries header
    var trackingEntriesHeader = new TrackingEntriesHeader(tracking.OutgoingHeaders.TrackingEntries);
    request.Headers.Add(trackingEntriesHeader);
    
    // pass headers via correlation state
    return tracking;
}

Now the SOAP message makes its journey to the service, where the WCF will create a respective message object and call IDispatchMessageInspector.AfterReceiveRequest on all message inspectors there.

Our TrackingDispatchMessageInspector deserializes the SOAP header, puts the information in a ITrackingInformation object, adds its tracking entry for receiving the message, and, again, returns the ITrackingInformation object as correlation state.

private ITrackingInformation GetTrackingInformation()
{
    var extension = new TrackingInformation();
    return extension;
}

object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
    // install operation extension
    var tracking = GetTrackingInformation();
    
    // tracking entries header
    var trackingEntriesHeader = TrackingEntriesHeader.ReadHeader(request.Headers);
    if (trackingEntriesHeader != null)
        tracking.IncomingHeaders.TrackingEntries.AddRange(trackingEntriesHeader.TrackingEntries);
    
    // add receive information
    tracking.IncomingHeaders.TrackingEntries.Add(new TrackingEntry(_thisService, "Received Request" ));
    
    // and pass on to outgoing headers
    tracking.OutgoingHeaders.TrackingEntries.AddRange(tracking.IncomingHeaders.TrackingEntries);
    
    // pass headers via correlation state
    return tracking;
}

The WCF proceeds to call the service method, the application developer provided. Afterwards the same process goes backwards for the reply. The WCF calls IDispatchMessageInspector.BeforeSendReply for all message inspectors. It also passes in the correlation state we returned earlier. Without this information we wouldn’t be able to link the two calls in case several requests came in in parallel.

Our message inspector adds the respective tracking entry, puts in in our header class, and is done:

void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
{
    var tracking = (ITrackingInformation)correlationState;
    
    // add send information
    tracking.OutgoingHeaders.TrackingEntries.Add(new TrackingEntry(_thisService, "Send Reply"));
    
    // tracking entries header
    var trackingEntriesHeader = new TrackingEntriesHeader(tracking.OutgoingHeaders.TrackingEntries);
    reply.Headers.Add(trackingEntriesHeader);
}

The SOAP message is sent back to the client. There the WCF again creates a message object and calls IClientMessageInspector.AfterReceiveReply for all message inspectors, passing in the correlation state, similar to what we saw on the server.

Our message inspector deserializes the SOAP header, adds its own tracking entry, and we’re done:

void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
{
    var tracking = (ITrackingInformation)correlationState;
    
    // tracking entries header
    var trackingEntriesHeader = TrackingEntriesHeader.ReadHeader(reply.Headers);
    if (trackingEntriesHeader != null)
        tracking.IncomingHeaders.TrackingEntries.AddRange(trackingEntriesHeader.TrackingEntries);
    
    // add receive information
    tracking.IncomingHeaders.TrackingEntries.Add(new TrackingEntry(_thisClient, "Received Reply from " + _calledService));
}

That’s it.

Let recap that in context: The application developer has put a service behavior on his service. This has lead to a respective contract behavior on the client. And with what we just provided, the two of them are working together at runtime to create a protocol of calls at runtime.

The final topic we have to address is making the information available to the developer.

 

That’s all for now folks,
AJ.NET

January 18, 2015

WCF Policy – Part 6: Implementation Basics

Filed under: .NET, .NET Framework, C#, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 12:37 pm

We’ve come pretty far, but we haven’t done anything worthwhile yet.

As a reminder: Our tracking policy is pretty simple: Client and server should keep track of sending and receiving messages, and accumulate that information along a request/reply call as part of the SOAP call. In the end this should create a timing protocol of the complete call.

So far we’ve got the design part covered: The server announces the policy, the client recognizes it. The next major aspect is actually doing something. In this post I’m going to provide some basics we are going to need further on. Classes to maintain the tracking information, as well as SOAP related helpers.

For a single tracking entry:

public class TrackingEntry
{
    public DateTime TimeStamp { get; private set; }
    public string Source { get; private set; }
    public string Reason { get; private set; }
    […]
}

TrackingHeaders combines the information going to the SOAP headers of one message, in our case a collection of tracking entries:

public class TrackingHeaders
{
    public List<TrackingEntry> TrackingEntries { get; private set; }
    […]
}

Since we have incoming and outgoing information, an interface abstracts the two of them, complemented with a respective class:

public interface ITrackingInformation
{
    TrackingHeaders IncomingHeaders { get; }
    TrackingHeaders OutgoingHeaders { get; }
}

internal class TrackingInformation : ITrackingInformation
{
    public TrackingHeaders IncomingHeaders { get; private set; }
    public TrackingHeaders OutgoingHeaders { get; private set; }
    […]
}

In case you are wondering about this setup: It’s modeled after the MessageHeaders class containing the headers natively supported by the WCF, and the way they are made available in the Message class.

We are going to include the information in the SOAP message as SOAP header – we do not want it to interfere with the actual contract and content – thus we need a MessageHeader class that deals with serialization/deserialization. Unfortunately the class supports only serialization of data based on data contracts, which in turn do not support XML attributes. Therefore, if more efficient XML is desired, one needs to take serialization into his own hands. Writing the header can be done by overriding the respective method:

internal class TrackingEntriesHeader : BaseMessageHeader
{
    public IEnumerable<TrackingEntry> TrackingEntries { get; private set; }
    
    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        foreach (var entry in TrackingEntries)
        {
            writer.WriteStartElement(NamespacePrefix, "Entry", Namespace);
            writer.WriteAttributeString("Source", entry.Source);
            writer.WriteAttributeString("TimeStamp", entry.TimeStamp.ToString("o"));
            writer.WriteAttributeString("Reason", entry.Reason);
            writer.WriteEndElement();
        }
    }
    […]
}

Reading the header includes looking it up, requesting a reader and actually reading it:

public static TrackingEntriesHeader ReadHeader(MessageHeaders headers)
{
    return (TrackingEntriesHeader)ReadHeader(headers, Defines.HeaderElementTrackingEntries, Defines.HeaderNamespace, ReadHeaderContents);
}

protected static TrackingEntriesHeader ReadHeader(MessageHeaders headers, string name, string ns, Func<XmlDictionaryReader, BaseMessageHeader> readHeaderContents)
{
    int headerIndex = headers.FindHeader(name, ns);
    if (headerIndex < 0)
        return null;
    
    // Get an XmlDictionaryReader to read the header content
    var reader = headers.GetReaderAtHeader(headerIndex);
    var header = readHeaderContents(reader);
    
    // NOTE: We must(!) remove ("consume") the header if MustUnderstand=1,
    // otherwise it will be considered "not understood" and an exception will be thrown.
    headers.RemoveAt(headerIndex);
    
    return header;
}

static BaseMessageHeader ReadHeaderContents(XmlDictionaryReader reader)
{
    reader.ReadStartElement(Defines.HeaderElementTrackingEntries, Defines.HeaderNamespace); // skip …
    var entries = new List<TrackingEntry>();
    while ((reader.LocalName == "Entry") && (reader.NamespaceURI == Defines.HeaderNamespace))
    {
        var entry = ReadEntry(reader);
        entries.Add(entry);
        
        reader.Read();
        if (reader.NodeType == XmlNodeType.EndElement)
            reader.ReadEndElement();
    }
    return new TrackingEntriesHeader(entries);
}

static TrackingEntry ReadEntry(XmlDictionaryReader reader)
{
    var source = reader.GetAttribute("Source");
    var timeStamp = reader.GetAttribute("TimeStamp");
    var message = reader.GetAttribute("Reason");
    var ts = DateTime.ParseExact(timeStamp, "o", null, DateTimeStyles.RoundtripKind);
    return new TrackingEntry(source, message, ts);
}

In case you’re wondering: Some of these methods reside in a separate base class, which I omitted to simplify things a bit; it will be included in the sample code, though. 

Now we have the bits and pieces we are going to need. In the next posts we’ll start using them to actually implement the policy.

 

That’s all for now folks,
AJ.NET

January 15, 2015

WCF Policy – Part 5: Addendum: Policy Support in WCF

Another addendum before we move on…

As MSDN states in regard to WS-Policy 1.2 and 1.5:

“WCF uses the WS-Policy specification together with domain-specific assertions to describe service requirements and capabilities.”

(In case you are wondering: you can choose the policy version for your service using configuration, namely the serviceMetadata element, policyVersion attribute; default is WS-Policy 1.2.)

Regarding WS-PolicyAttachment the claim is:

“WCF implements WS-PolicyAttachment to attach policy expressions at various scopes in Web Services Description Language (WSDL).”

Sounds great, doesn’t it? But if you read carefully, WCF “using” WS-Policy and “implementing” WS-PolicyAttachment to achieve something actually does not imply fully supporting it.

 

The one pitfall I have found is the way policy expressions are identified and referenced. WS-Policy supports two ways to identify policy expressions, either by a Name attribute, or by a wsu:Id attribute (as shown in part 2 of this series). wsu:Id is used to identify policies residing in the same XML document, Name becomes necessary for policies in separate XML documents, for example imported using wsdl:import. The pitfall I mentioned: WCF does not support policies in separate XML documents, i.e. policy references using the Name attribute.

Now, as long as you are working within WCF on both client and server, this will never be an issues. However if your policy is provided by a Java Metro service, there is a choice, as documented here. Example 19.1 works fine with WCF clients, examples 19.2 and following are not supported. Other technologies may provide similar options, or – even worse – be limited to the Name attribute.

It’s not as if Microsoft doesn’t know the standards, they explained it quite well in “Understanding Web Services Policy”, chapter 2.8, “Referencing Policy Expressions”. They also know about the issue. Unfortunately they are not going to do something about it:

“At this point of time WCF only supports policies included in the same WSDL file and identified via the wsu:ID attribute.
Unfortunately, we are not seeing large customer demand supporting policies residing in secondary WSDL documents, so I will be resolving this bug as "Wont Fix".”

Sic!

Having had to support both, .NET and Java, I ended up writing a little command line application, that downloads and patches the WSDL of services using the Name attribute…

 

That’s all for now folks,
AJ.NET

December 14, 2014

WCF Policy – Part 4: Addendum: Creating the Client Proxy via Command-Line

Filed under: .NET, .NET Framework, C#, Design Time, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 12:52 pm

A minor addendum to the last post

Last time I described the client proxy generation as it happens from within Visual Studio (“Add service reference…”). For those who want to use the command line tool svcutil.exe, there are a few things to keep in mind:

  • It is not sufficient, to provide the app.config via the /config parameter. This configuration file is only for output; to provide a configuration file as input you need to pass it in via the /svcutilConfig parameter.
  • Additionally the assembly containing the import extension has to be found by svcutil.exe. This works automatically if the assembly resides in the GAC. In other cases the assembly has to be provided using the /reference parameter.
  • Lastly the namespace for the generated code needs to be provided as it is not automatically inferred by the tool. This involves a somewhat awkward syntax…

All together results in a command line similar to this (line feeds for better readability):

svcutil
    /config:app.config
    /svcutilConfig:app.config
    /reference:TrackingPolicy.ServiceModel.dll
    /namespace:*,TrackingPolicy.TestClient.TestService
    http://localhost:33333/Services/TestService.svc?singleWsdl

Best put in in a batch file, you don’t wan to retype that every time…

That’s all for now folks,
AJ.NET

December 7, 2014

WCF Policy – Part 3: Evaluating the Policy on the Client

The last part placed our policy assertion in the WSDL:

On the client the WCF evaluates policy assertions during proxy generation, for code and configuration. If you try to import a WSDL containing a policy assertion, the WCF does not know – as is the case with our policy assertion so far – the generated configuration will contain the following warning:

To provide respective import logic the WCF provides an interface IPolicyImportExtension. While this is conceptually similar to what is provided for the export, there is one difference: It is not placed on a binding. In fact, it would not make sense to put it on a binding, as the binding configuration configuration does not yet exist; rather it is part of what is going to be generated during the import. That is why the interface has to be implemented by an arbitrary class, which has then to be announced in the configuration:

During import the WSDL will call respective extensions for all policies it finds. Our job is to check whether the we know the policy assertion. If so, we need to remove it, to prevent the above warning from showing up. Within IPolicyImportExtension.ImportPolicy and it with its parameter of type PolicyConversionContext, this is just one line of code to satisfy the WCF and get rid of the warning:

Now we need to do something with our policy assertion. For our tracking policy I want to place a contract behavior on the generated contract, similar to the service behavior on the server side. This is supported by yet another interface, namely IServiceContractGenerationExtension, and again, on behaviors. So we provide a respective behavior and let our importer add that behavior for the contract. Just one additional line of code:

Still during proxy generation, but some time after our importer has done its job, the WCF will call IServiceContractGenerationExtension.GenerateContract on our behavior. At this time the actual contract interface will have already been created using CodeDOM, so we can party on it and manipulate it as we like. In our case add a contract behavior attribute:

All other methods of the behavior are simply empty. Of course we also need to provide the TrackingContractBehaviorAttribute, also – for the time being – with empty methods.

Note: Strictly speaking, we could use the behavior class. But I want to emphasis the fact that the behavior used to manipulate the code is only present during proxy generation, while the one we just added as attribute is present at runtime.

Running the import again will remove the warning in the configuration. And it will also create a contract amended with our attribute:

In case the policy contains more complex parameters, there is more work to do – analyzing the XML from the policy assertion, generating code with parameters – but the general principle stays the same.

This completes the design time aspects of our policy. The following image depicts the process on server and client (i.e what we covered this post and the last) in overview:

First order of the day fulfilled. The service announces the policy in the WSDL for everyone to take notice and act accordingly. The client proxy generation can be taught to evaluate the policy assertion. What’s important: The bridge between server and client is the WSDL and WS-Policy – common standards, nothing WCF-specific. Similar mechanisms can also be set up on other platforms, e.g. Java with Metro.

The next post will be an addendum, before we take care about the runtime aspects. After all, our implementation doesn’t do anything worthwhile yet.

 

That’s all for now folks,
AJ.NET

November 29, 2014

WCF Policy – Part 2: Advertising the Policy

Filed under: .NET, C#, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 12:40 pm

The last post provided the introduction about what “policy” in the context of WCF is about. Now we are going to go ahead and actually build our own policy.

Note: This post is part of a series. The TOC can be found here

Defining the policy

For this endeavor we keep the actual functionality simple: During a service call, client and server are to add timestamps whenever a message goes out or comes in. Those timestamps shall be maintained in a list that is forwarded with each message, doing so as SOAP header, since this is not part of the regular contracts. This will create a trace of the whole request/response chain. (“Chain” may sound a little presumptuous, but if one service calls others, this might become more of a challenge.) We’ll call this (a little snobbish) “tracking policy”.

Configuring the policy

The first step of the implementation is relatively unspectacular. Since we want to influence the behavior of the service, we need some kind of WCF behavior. I chose a service behavior, other demands may call for a different behavior type. The canonical implementation for a respective attribute looks like this…

… with all the method bodies empty. This is sufficient to be put on a service:

For details on behaviors (including extension elements to be used in configuration rather than code) see here.

Publishing the policy

Now for the first interesting part: How do we insert a policy assertion for our policy into the WSDL? WCF supports writing policy assertions via IPolicyExportExtension, however only for binding elements, not for behaviors. Of course we could provide a respective binding element and ask the developer to configure it – on top of the behavior that he already put on his service. Not exactly comfortable and a source of errors.

There is an alternative, though: Our behavior can add the binding element during the IServiceBehavior.Validate call, as shown here:

(This depends on the employment of a custom binding. I will address the question of other bindings in a later post.)

Now, IServiceBehavior.Validate is obviously not intended for this kind of manipulations, but what the heck, it works, and it makes things easier for the application developer.

Whenever the WSDL is generated, the binding elements implementing IPolicyExportExtension will be asked to insert their policy assertion. IPolicyExportExtension.ExportPolicy will be called and the parameter of type PolicyConversionContext provides the plumbing we need. The policy assertion itself is nothing more than an arbitrary XML fragment – the identifying part is an XML element – which we can create on the fly:

With this code in place, the WSDL should include the XML we just generated. Perhaps in combination with other policy assertions, depending on how the service is configured, but similar to this:

In our case we only needed the existence of the XML element to publish the policy. More complex policies may need to publish additional information. In this case all you need to do is to include XML attributes and/or elements as you like as children of the root element of the policy assertion. WS-Security Policy goes even further and provides several different policy assertions.

That concludes the server perspective for our policy assertion. The next post will look at it from the client perspective.

That’s all for now folks,
AJ.NET

Older Posts »

Blog at WordPress.com.