I just dived a little deeper into it and discovered new details.
Not the 'UriTemplate' in general causes the 2nd invocation of 'AfterReceiveRequest' but the optional parameter within!
If I call the method by "http://server/result/val1" AfterReceiveRequest will be invoked twice.
If I pass all possible parameters like "http://server/result/val1/val2/val3" there will be no useless invocation. Is that behavior as intended?
UriTemplate = "result/{para1=null}/{para2=null}/{para3=null}"
--- following the initial post, just for information ---
While implementing a WCF REST Service System I stuck on a problem with the http-headers.
In my `ServiceContract` there is a method with an `UriTemplate` definition at the `WebGet` attribute, so it can be called via
http://server/result/val1/val2 ...
instead of
http://server/MyMethod?para1=val1¶2=val2 ...
(I need this because of compatibility reasons.)
Also there is a significant value in the http-headers collection, that I need to read. Therefore I implement `IDispatchMessageInspector` and add this inspector to the `EndpointDispatchers` `MessageInspectors` collection. By that the `AfterReceiveRequest` will
be invoked by WCF and I can access `WebOperationContext.Current.IncomingRequest.Headers` to read the desired Value.
The Problem:
WCF solves the `UriTemplate`-mapping by generating a second request to the destination method, but does not pass the header entries from the original call to the generated second call. So `AfterReceiveRequest` (and of course `BeforeSendReply`, too) will
be invoked twice, but the header-values from the real client call are only included in the first call.
Also I found no way to correlate the first and the second `AfterReceiveRequest` call, to implement a "special way" for passing the header-value from the first to the second call.
Is there a way to tell WCF to route the headers to the `UriTemplate`-redirected second call?
Here are some code fragments to make it clear:
[ServiceContract]
public interface IMyService
{
[WebGet(UriTemplate = "result/{para1=null}/{para2=null}/{para3=null}")]
bool MyMethod(string para1, string para2, string para3);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
[MyServiceInspectorBeavior]
public class MyService : IMyService
{
public bool MyMethod(string para1, string para2, string para3)
{
return DoTheWork();
}
//...
}
public class MyServiceInspectorBeavior : Attribute, IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (EndpointDispatcher epDispatcher in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>().SelectMany(cDispatcher => cDispatcher.Endpoints))
{
epDispatcher.DispatchRuntime.MessageInspectors.Add(new MyInspector());
}
}
//...
}
public class MyInspector : IDispatchMessageInspector
{
//this is invoked twice for each client request,
//but only at the first call the header is present...
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
WebHeaderCollection webOpContext =
WebOperationContext.Current.IncomingRequest.Headers;
string xForwardedIp = webOpContext["X-FORWARDED-IP"];
WriteLog(xForwardedIp);
return OperationContext.Current.IncomingMessageProperties["ActivityId"];
}
//...
}