I would to intercept all post request to a custom WCF service (.net 3.5 SP1) in order to validate the presence of a specific header.
What I tried so far:
public class ServiceFactory : WebServiceHostFactory
{
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var result = base.CreateServiceHost(serviceType, baseAddresses);
result.Opened += result_Opened;
return result;
}
private void result_Opened(object sender, EventArgs e)
{
var ctx = HttpContext.Current;
var request = ctx.Request;
if (request.HttpMethod == "POST")
{
// Validate if the request contains my header
if(request.Headers["MyHeader"] != "42")
throw new VeryBadThingsException("boom");
}
}
}
I also set up my svc files to use this factory.
This is sometimes working. Actually, not all my web services calls are hooked by the open event handler. The web service actual implementation is reached, so I suppose the problem is not the web service itself.
What should I do to correctly hook all incoming requests to my service?
PS: to descbribe a bit more my context, the service is hosted by SharePoint 2010. That means I can't change the web.config file (technically it's possible, but it's a pain to deploy and maintain).
And I acutally inherits the class Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory
Ok, I manage to swim between all objects, with the help of the code project article Add Custom Message Header in WCF 4 Calls.
Especially, it helped me to figure out how to properly attach a ServiceBehavior through code, using attributes.
I finally have this:
internal class ValidateSPFormDigestAttribute : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase host)
{
foreach (ChannelDispatcher cDispatcher in host.ChannelDispatchers)
{
foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
{
eDispatcher.DispatchRuntime.MessageInspectors.Add(new ValidateSPFormDigestInspector());
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
internal class ValidateSPFormDigestInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (!SPUtility.ValidateFormDigest())
{
throw new FaultException(new FaultReason("Invalid form digest token"));
}
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
}
And I attach my custom behavior on the service directly:
[BasicHttpBindingServiceMetadataExchangeEndpoint]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ValidateSPFormDigest]
public class MyCustomService: IWidgetAdminService
The immediate benefits, is that I no more require creating a custom web service factory!