tags:

views:

428

answers:

2

I'm truly stumped. I've tried every tool imaginable, checked every resource I can, and still can't make sense of this.

I have a WCF service designed to handle plain old XML requests in a proprietary XML format (this is an old ASMX conversion). I've setup the service using the WCF 3.5 to accept plain HTTP POST requests, and it works beautifully as long as the Content-Type in the request header is not set to "text/xml" (or any other XML or JSON type, such as "text/json" or "application/json").

In other words, if I set the content type of the request to "text" or "text/plain" or even "whatever", the service works as expected. However, when I set the content type to "text/xml", the service fails with an HTTP 400 Bad Request.

And I've failed to find a way to debug the failure to get some more information. The actual service method is never called, and implementing IErrorHandler didn't catch an error either. I'm suspecting something is wrong with my WCF config or with my IIS 7 setup, but I'm absolutely clueless as to what is going on.

Here's my service contract:

using System.ServiceModel;
using System.ServiceModel.Web;
using System.IO;

namespace App.api.v_1_1
{
    [ServiceContract]
    public interface IPlainXmlWebServiceViaHttpPost
 {
        [WebInvoke(UriTemplate = "", BodyStyle = WebMessageBodyStyle.Bare, Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
        [OperationContract]
  Stream Process(Stream xml);
 }
}

And here's my service implementation:

using System.IO;
using System.ServiceModel.Activation;
using App.api.v_1_0;
using System.ServiceModel;

namespace App.api.v_1_1
{
    [ServiceBehavior(Namespace = Constants.WebServiceNamespace)]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class PlainXmlWebServiceViaHttpPost : IPlainXmlWebServiceViaHttpPost
 {
        public Stream Process(Stream request)
        {
            return request.ProcessTextStreamWith(PoxProcessor.Process);
        }
 }
}

Basically it's just turning the incoming Stream into a string, doing something with that string, and returning a string response converted back into a Stream. The idea is to be able to pass arbitrary XML to the service and return arbitrary XML.

And, finally, here's the relevant portion of the web.config:

<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <bindings>
        <webHttpBinding>
            <binding name="poxBinding" maxReceivedMessageSize="655360">
                <readerQuotas maxArrayLength="655360" />
                <security mode="None">
                    <transport clientCredentialType="None" />
                </security>
            </binding>
        </webHttpBinding>
    </bindings>
    <behaviors>
        <endpointBehaviors>
            <behavior name="REST">
                <webHttp />
            </behavior>
        </endpointBehaviors>
        <serviceBehaviors>
            <behavior name="poxBehavior">
                <serviceDebug httpHelpPageEnabled="false" includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service behaviorConfiguration="poxBehavior" name="App.api.v_1_1.PlainXmlWebServiceViaHttpPost">
            <endpoint address="" behaviorConfiguration="REST" binding="webHttpBinding"
                bindingConfiguration="poxBinding" contract="App.api.v_1_1.IPlainXmlWebServiceViaHttpPost" />
        </service>
    </services>
</system.serviceModel>

I've been trying all sorts of workarounds to get WCF/IIS to cooperate with me, and all have failed. Does anyone know what would cause requesting the expected content types to return HTTP 400, but all other content types to be processed as expected?

+2  A: 

A couple of thoughts for you. You might take a look at the rest starter kit. They have created a bunch of extra stuff to help with building restful services and have a ton of great examples.

The other thing to try when trouble shooting wcf services is to turn on messaging logging. You can do that in your config file like this:

<system.serviceModel>
<diagnostics>
  <messageLogging logMalformedMessages="true" logMessagesAtServiceLevel="false"
   logMessagesAtTransportLevel="true" />
</diagnostics>

The log files can be read with SvcTraceViewer.exe (My is located here: C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin). I believe this tool comes with the Windows SDK. The config editor (SvcConfigEditor.exe) found in the same location can be used to help edit your web.config. There are other options for what to log if you click on the 'Diagnostics' folder after loading your config file into the editor.

Tim Clem
Thanks Tim, that's very helpful. Ultimately the problem turned out to be what Darin pointed out: I had not assigned the WebServiceHostFactory in my .svc markup file.
adamjcooper
+3  A: 

Did you use WebServiceHostFactory in your .svc file:

<%@ ServiceHost 
    Factory="System.ServiceModel.Activation.WebServiceHostFactory"   
    Service="App.api.v_1_1.PlainXmlWebServiceViaHttpPost" 
%>
Darin Dimitrov
Darin, it turns out this was exactly what was wrong. Thanks so much.
adamjcooper