I have a REST service in C# as shown below :
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(UriTemplate="/GetData"]
[OperationContractAttribute(Action = "urn:crud:insert/IService1/GetData")]
string GetData(string value);
}
When I send my custom header details to ServerMessageInspector, then I am always getting action property as null
public class StringTrimmingMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request,
IClientChannel channel, InstanceContext instanceContext)
{
if(request.Header.Action!=null) // Issue : this property is always null
{
}
}
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
Would you please help or suggest me how can i set this property, same example works fine when i use WCF service but my requirement to use REST service only.
Related
All,
I am having couple of WCF services and one rest service which uses ClientMessageInspector and ServerMessageInspector for token Authentication.
Is there any way to find out in ClientMessageInspector and ServerMessageInspector whether request coming from WCF or REST
Something like in ClientMessageInspector
public class ClientMessageInspector : IClientMessageInspector {
public object BeforeSendRequest (ref Message request, IClientChannel channel) {
if (request header is WCF) {
// Do Something
} else if (request header Rest) {
// Do Something
}
}
}
Something like in ServerMessageInspector
public class ServerMessageInspector : IDispatchMessageInspector {
public object AfterReceiveRequest (ref Message request, IClientChannel channel, InstanceContext instanceContext) {
if (request header is WCF) {
// Do Something
} else if (request header Rest) {
// Do Something
}
}
}
i am creating the REST service with POST method and OBJECT as input param. while client request am unable to get the actual JSON data client have posted. Is there any way to dig the JSON code from the C# WCF service.
My code:
namespace ACTService
{
public class AssortmentService : IAssortmentService
{
public void DeleteColor(DeleteColorContarct objdelcolor)
{
new Methods.ColorUI().DeleteColorDetails(objdelcolor);
}
}
}
and my interface as
namespace ACTService
{
[ServiceContract]
public interface IAssortmentService
{
[OperationContract]
[WebInvoke(UriTemplate = "DeleteColor", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json,BodyStyle=WebMessageBodyStyle.Wrapped)]
void DeleteColor(DeleteColorContarct objColor);
}
}
I need to access the JSON format in other class file ColorUI
WCF provides a lot of extensible points one of them is a feature called MessageInspector. You can create a custom message inspector to receive the request before it get de-serialized to C# object. And do what ever you can with Raw request data.
In order to implement it you would need to implement System.ServiceModel.Dispatcher.IDispatchMessageInspector interface like below:
public class IncomingMessageLogger : IDispatchMessageInspector
{
const string MessageLogFolder = #"c:\temp\";
static int messageLogFileIndex = 0;
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
string messageFileName = string.Format("{0}Log{1:000}_Incoming.txt", MessageLogFolder, Interlocked.Increment(ref messageLogFileIndex));
Uri requestUri = request.Headers.To;
HttpRequestMessageProperty httpReq = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
// Decode the message from request and do whatever you want to do.
string jsonMessage = this.MessageToString(ref request);
return requestUri;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
}
Here's the complete code snippet gist. Actual source.
Now you need to add this Message inspector to end point behavior. To achieve that you would be implementing System.ServiceModel.Description.IEndpointBehavior interface like below:
public class InsepctMessageBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new IncomingMessageLogger());
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
Now if you are on selfhosting i.e. you are hosting your service programmatically you can directly attach this newly implemented behavior to your service end point. E.g.
endpoint.Behaviors.Add(new IncomingMessageLogger());
But If you have hosted the WCF Rest service in IIS then you would be injecting the new Behavior via configuration. In order to achieve that you have to create an additional class derived from BehaviorExtensionElement:
public class InspectMessageBehaviorExtension : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(InsepctMessageBehavior); }
}
protected override object CreateBehavior()
{
return new InsepctMessageBehavior();
}
}
Now in your configuration first register the behavior under system.servicemodel tag:
<extensions>
<behaviorExtensions>
<add name="inspectMessageBehavior"
type="WcfRestAuthentication.MessageInspector.InspectMessageBehaviorExtension, WcfRestAuthentication"/>
</behaviorExtensions>
</extensions>
Now add this behavior to the Endpoint behavior:
<endpointBehaviors>
<behavior name="defaultWebHttpBehavior">
<inspectMessageBehavior/>
<webHttp defaultOutgoingResponseFormat="Json"/>
</behavior>
</endpointBehaviors>
set the attribute behaviorConfiguration="defaultWebHttpBehavior" in your endpoint.
That's it your service will now capture all the messages before deserializing them.
I'm having trouble with implementing URL redirection using message inspectors for my WCF REST service. The idea is to implement AfterReceiveRequest to change the incoming request to effectively do nothing, and then in BeforeSendReply, make call to another URI which provides the actual service. You can think of this scenario as something where we do not want to break clients, so they continue to use old URIs for invocations, but internally we redirect them to a different URI.
For example, this is what my service contract looks like:
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(UriTemplate = "person/{person}")]
string GreetMe(string person);
[OperationContract]
[WebGet(UriTemplate = "donothing")]
string DoNothing();
}
And this is the implementation:
public class Service1 : IService1
{
public string GreetMe(string person)
{
return string.Format("Hi {0}", person);
}
public string DoNothing()
{
return string.Empty;
}
}
Then I'm adding a MessageInspector to endpoint behavior. The AfterReceiveRequest of this inspector is like this:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
OperationContext operationContext = OperationContext.Current;
if (WebOperationContext.Current != null && WebOperationContext.Current.IncomingRequest.UriTemplateMatch != null)
{
UriBuilder baseUriBuilder = new UriBuilder(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri);
UriBuilder requestUriBuilder = new UriBuilder(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri);
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRootUri"] = baseUriBuilder.Uri.ToString();
OperationContext.Current.IncomingMessageProperties["MicrosoftDataServicesRequestUri"] = baseUriBuilder.Uri.ToString() + "donothing";
OperationContext.Current.IncomingMessageHeaders.To = new Uri(baseUriBuilder.Uri.ToString() + "donothing");
operationContext.IncomingMessageProperties["Via"] = new Uri(baseUriBuilder.Uri.ToString() + "donothing");
request.Headers.To = new Uri(baseUriBuilder.Uri.ToString() + "donothing");
}
return null;
}
Basically, I want to change all incoming requests to go to DoNothing() operation. However, when I run this, I still see that the request makes it to GreetMe method. I attached the debugger and can see that my code in AfterReceiveRequest is getting executed, but I'm not sure why the URI redirection does not happen.
Any ideas?
I am trying to make an echo web service that replies back with the request content, regardless of what that content is. Just an endpoint listening for anything and spitting it back.
So for example if it is called with "hi", the response content is "hi". If it is called with a multi-part message containing a form data, the data comes back. If it is a JSON message then JSON comes back. This is regardless of what the actual content is or what url parameters are provided. Basically I want it to send the same thing back regardless of the mime type, don't try to interpret it, just spit it back.
I'm starting with the following:
[ServiceContract]
private interface IEchoService
{
[OperationContract]
[WebInvoke]
object Echo(object s);
}
private class EchoService : IEchoService
{
public object Echo(object s)
{
return s;
}
}
WebServiceHost host = new WebServiceHost(typeof(EchoService), new Uri("http://localhost:8002/"));
WebHttpBinding binding = new WebHttpBinding();
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IEchoService), binding, "echo");
Any ideas how to make this work? This just returns back a HTTP status code of bad request when called.
It looks like the answer is to use the System.ServiceModel.Channels.Message class.
[ServiceContract]
private interface IEchoService
{
[OperationContract]
[WebInvoke]
Message Echo(Message s);
}
private class EchoService : IEchoService
{
public Message Echo(Message s)
{
return s;
}
}
I have implemented a WCF inspector in my client application that consumes numerous web services.
I am using this inspector as a logging mechanism to log calls sent from the application to those web services and the responses they give back.
public class WcfClientInterceptor : IClientMessageInspector
{
protected static readonly ILog log4net = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly IMessageLogger Logger = new Log4NetLogger();
private MessageLogEntry LogEntry;// = new MessageLogEntry();
public void AfterReceiveReply(ref Message reply, object correlationState)
{
if (Logger.IsLogEnabled)
{
LogEntry.ResponseBody = reply.ToString();
Logger.Log(LogEntry);
}
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (Logger.IsLogEnabled)
{
LogEntry = LogEntry ?? new MessageLogEntry();
//instanceContext.GetServiceInstance().GetType().Name
//LogEntry.WebServiceIdentity = request.Headers.Action;
LogEntry.WebServiceIdentity = OperationContext.Current.IncomingMessageHeaders.Action;
LogEntry.RequestBody = request.ToString();
}
return null;
}
}
My problem is that I don't know what web service is called. I want to get some kind of reference to them and log it.
This is the only method that works request.Headers.Action but it doesn't always work. Most of the time this is String.Empty.
OperationContext.Current is null which I understand is normal on the client side.
Is there any other way of getting the name of the webservice that is called?
or the name of the calling method? or something?
Thank you
it works with LogEntry.WebServiceIdentity = request.Headers.Action;
I made a mistake