Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTTP Bad Request error when requesting a WCF service contract

I have a WCF service with the following configuration:

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MetadataEnabled">
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
     </behaviors>
      <services>
          <service behaviorConfiguration="MetadataEnabled" name="MyNamespace.MyService">
              <endpoint name="BasicHttp"
                        address=""
                        binding="basicHttpBinding"
                        contract="MyNamespace.IMyServiceContract" />
              <endpoint name="MetadataHttp"
                        address="contract"
                        binding="mexHttpBinding" 
                        contract="IMetadataExchange" />
              <host>
                  <baseAddresses>
                      <add baseAddress="http://localhost/myservice" />
                  </baseAddresses>
              </host>
          </service>
    </services>
</system.serviceModel>

When hosting the service in the WcfSvcHost.exe process, if I browse to the URL:

http://localhost/myservice/contract

where the service metadata is available I get an HTTP 400 Bad Request error.

By inspecting the WCF logs I found out that an System.Xml.XmlException exception is being thrown with the message: "The body of the message cannot be read because it is empty."
Here is an extract of the log file:

<Exception>
<ExceptionType>
System.ServiceModel.ProtocolException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</ExceptionType>
<Message>There is a problem with the XML that was received from the network. See inner exception for more details.</Message>
<StackTrace>
at System.ServiceModel.Channels.HttpRequestContext.CreateMessage()
at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, ItemDequeuedCallback callback)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult result)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContext(IAsyncResult result)
at System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.ListenerAsyncResult.WaitCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<InnerException>
<ExceptionType>System.Xml.XmlException, System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The body of the message cannot be read because it is empty.</Message>
<StackTrace>
at System.ServiceModel.Channels.HttpRequestContext.CreateMessage()
at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, ItemDequeuedCallback callback)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult result)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContext(IAsyncResult result)
at System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.ListenerAsyncResult.WaitCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
</InnerException>
</Exception>

If I instead browse to the URL:

http://localhost/myservice?wsdl

everything works just fine and I get the WSDL contract. At this point, I can also remove the "MetadataHttp" metadata endpoint completely, and it wouldn't make any difference.

I'm using .NET 3.5 SP1. Does anyone have an idea of what could be wrong here?

like image 479
Enrico Campidoglio Avatar asked Nov 27 '08 11:11

Enrico Campidoglio


2 Answers

Generally this is a problem with the size of the SOAP envelop. Check your binding configuration in order to change MaxBufferPoolSize, MaxReceivedMessageSize to allow huge contents. Remember, you must change both in client and server sides.

Another issue is the MessageEnconding (another binding parameter), ensure that client and server side are using the same encoding.

Finally, check the Reader Quotas Properties parameters.

like image 95
Luty Avatar answered Sep 20 '22 20:09

Luty


I think I found out what the problem is.

If I browse to the URL:

http://localhost/myservice/contract

with the WcfTestClient application I can successfully retrieve the service metadata.
So the error really only occurs when I request the URL through a web browser.

The HTTP Bad Request error comes from the fact that the browser issues an HTTP GET request where the contents of the message are in the HTTP headers, and the body is empty.
This is exactly what the WCF mexHttpBinding is complaining about!

In order to get to the service contract via a web browser you will have to explicitly enable it in the service behavior:

<serviceBehaviors>
    <behavior name="MetadataEnabled">
        <serviceMetadata httpGetEnabled="true" />
    </behavior>
</serviceBehaviors>

The URL to request becomes then:

http://localhost/myservice?wsdl

So, it turns out I was a little too quick in posting this question. However, I'll keep it anyway just for the record.

like image 27
Enrico Campidoglio Avatar answered Sep 21 '22 20:09

Enrico Campidoglio