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:/ /myserver/result/val1
AfterReceiveRequest will be invoked twice.
If I pass all possible parameters like
http:/ /myserver/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/resource/val1/val2 ...
instead of
http://server/resource?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 theUriTemplate
-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"];
}
//...
}