Last time we were looking at the problem of securing a dynamically generated message header. We saw one solution to that problem, which was to add a behavior that updated the protection level for the desired message part. That solution is quite simple but it isn't perfect. The execution of this behavior comes rather late. Anyone that inspects the service description in the meantime, such as for metadata generation, won't see the protection level that we want to use.
How early can we make the update to the security settings? Well, potentially very early. We could subclass ServiceHost and override ApplyConfiguration to make the changes during creation of the host. That may even be too early as it prevents us from working with anything that is added to the service description through code rather than configuration. However, we could similarly make the changes some time after we get the service host object back but before it was opened. This would let us plug in before any behaviors started execution. The choice is yours.
The downside of this method is that it is a more treacherous route to get to the message header. Starting from the service host we need to get the endpoint that we're going to modify (usually by contract or address). From the endpoint we can get the operation by action name. From the operation we can get the right message by name. The default names are canonically derived from the operation action and direction. Unlike before, separating incoming and outgoing messages here is a lot murkier. From the message though, we can refer to the message header in the same way and set its protection level. Here's all of that in code using some example values.
ServiceEndpoint endpoint = host.Description.Endpoints.Find(typeof(IService));
OperationDescription operation = endpoint.Contract.Operations.Find("Action");
MessageDescription message = operation.Messages.Find("http://tempuri.org/IService/ActionResponse");
MessageHeaderDescription header = message.Headers[new XmlQualifiedName("aheader", "http://tempuri.org/")];
header.ProtectionLevel = ProtectionLevel.Sign;
Next time: Keeping Traces Up to Date