Divis Blog

Just another geeks blog.

REST in REST is not a good idea

clock January 23, 2009 16:58 by author Divi

Hi all,

Today I spent some time wrinting a wrapper for an old REST service to make it read its data from a newer service. Unfortunately it seemed to be a little more complicated than I thought. As I just thought I’d have finished my work, I got the following error message:

(The remote server has responded with an unexpected answer: Method Not Allowed.)


Oops? A protocol error? What have I done? That nettled me that much that I decided to fix it instead of hurry myself and write a workaround for it. At first I thought it could be a configuration fault … but that it wasn’t … after I built a test-solution in VisualStudio for this structure, I could confirm my suspicion. The above named “method” in the error message has been the kind of transmission between the services. My REST-service expected a GET-request, but strangely my client sent a the request via POST:

Because of this I checked the definition of my contracts, if my fault could be there, but everything seemed to be right. Originally I used the WebGet attribute, but also the WebInvoke with “Method”=”GET” made no difference.

After I sat there for some time and couldn’t believe that it should be an error of WCF itself, I put a web-form for, testing reasons, in the same directory as my *.svc file and copied the service request in there … it worked:

So let’s note down – if I call a REST-service by another REST-service with a REST-client, I get as method alwas „POST“ … if I copy exactly the same code and configuration into a web-form and invoke it there, I get a „GET“-request (if I want to) … for the moment that seems to be a problem I can’t fix myself.

But even if you can’t get it to work THAT way, you could still use „POST“ instead of the „GET“ method. This will work in both places. The only negative thing is that you can’t call the service directly by opening the specific request in your browser. If you can’t use another method than “GET”, you could still use the HttpWebRequest directly for invoking the service.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Adding MessageInspectors

clock January 17, 2008 01:46 by author Divi

After some time ago noone could explain to me at tutorials.de how to log incoming and outgoing messages in WCF, I thought I should tell share my knowledge about that with you:

WCF offers a configuration for MessageLogging by default. These are the so called "Diagnostics" and absolutely sufficient if you're really just trying to log something. The related article about that you can find at the MSDN.

Unfortunately the logging can't be configured as detailed as I needed it at that time. My task was to store the sent message related to an object, to check wheter the preprocessing wrapper does its job.

After some searching I found the way of the "Extensions". And that works as follows:

You can set the endpoint in the configuration and attach an Endpoint-Behavior::

<endpoint address="ADDRESS" binding="basicHttpBinding" behaviorConfiguration="AttachClientInspector" contract="CONTRACT" />

Therefore a "Behavior" named "AttachClientInspector" needs to be created (Of course you can chose the name yourself). This one would look somewhat look like this:

<endpointBehaviors>
  <behavior name="AttachClientInspector">
    <ClientInspector />
  </behavior>
</endpointBehaviors>

If you're using Visual Studio 2005, just don't wonder why the "ClientInspector"-Tag is beeing marked with the description "...invalid child element". That's just because the VS2005 doesn't recognize the Extension itself. And that's the next step you have to do. The config section "System.ServiceModel" allows subsections named "Bindings", "Behaviors" and "Extensions". Here you can add your "BehaviorExtension":

<behaviorExtensions>
  <add name="ClientInspector " type="CLASSNAME, ASSEMBLYNAME, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>

Of course the CLASSNAME has to point on a specific class, which is qualified for inspecting the message. To make sure that the class is accepted for this, you have to derive it from "System.ServiceModel.Configuration.BehaviorExtensionElement" AND implement "System.ServiceModel.Description.IEndpointBehavior". You have to derive from BehaviorExtensionElement, to use the class as an extension for the behavior. It requires the allocation of BehaviorType, where you can just return the current class via typeof and the method CreateBehavior, where you just have to return an instance of the current class.

public override Type BehaviorType
{
    get { return typeof(CLASSNAME); }
}

protected override object CreateBehavior()
{
    return new CLASSNAME();
}

On the other hand IEndpointBehavior provides the methods which are called, when the extension is executed at runtime. The interesting method for us should be: "ApplyClientBehavior". This method has a parameter "clientRuntime" of the same-named type. Here you can now attach the inspector as follows:

clientRuntime.MessageInspectors.Add(new CUSTOMINSPECTOR());

So... that's the key thing, to call our inspector as soon as the Endpoint is beeing used. Now there's only missing the implementation of the inspector itself. Therefore you have to create a class named CUSTOMINSPECTOR (the uppercase words are just placeholders to demonstrate the relations) and derive it from the type "System.ServiceModel.Dispatcher.IClientMessageInspector". This interface adds two methods. AfterReceiveReply and BeforeSendRequest. The second one awaits a return value of the type "object"... simply write "return null;" into this method and everything works fine.

If you now hit the compile button, everything should build without any problems. Now we have to add the implementation of the inspector. Therefore both methods have parameters of the type "System.ServiceModel.Channels.Message". In these parameters there's the real message contained.

If you're now trying to use that object, I guess it won't last a long time until you're getting stressed up, because the message-object is getting invalid, as soon as you read any information out of it. Cool, isn't it? ;-)

But you can solve that problem also very easily, because the message-objects contain a method called "CreateBufferedCopy". By calling that method you can create a "buffered copy" of the current message-object:

MessageBuffer bufferedMessage = request.CreateBufferedCopy(request.ToString().Length);

(Here's the message-object "request". In the "AfterReceiveReply" the object is called "reply".)

 

You can modify the "buffered copy" as often as you want and create a message object again after your analysis has finished:

 

request = bufferedMessage.CreateMessage();

(And as already told - again: The parameter of the reply-method is "reply". The object which is filled here, has to be the same as passed to the current method.)

 

All you have to know about it is - you've got several ways to analyze the content of the message:

1.) You can create a XPathNavigator with the method "CreateNavigator" out of the "bufferedMessage", with which you can analyze the xml itself. Over that you can access the content at any part of the XPathNavigator via its property "InnerXML". This one contains the content of the current node as a plaintext-string.

2.) You can also, as already said before, use ToString on the request object, which will return the content of the message (The envelope).

I wish a lot of fun with that and hope I could help you!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5