IIS returns 400 “bad request” for WCF service file


This is an IIS hosted WCF service uses basicHttpBinding in NLB environment. The configuration looks like below. It had been worked well for years.

<service name=”MyService”>

    <endpoint address=”https://NLB_Virtual_Name.Organization.Company.Com/MyService/MyService.svc” binding=”basicHttpBinding”     contract=”IMyService”…./>

     <endpoint contract=”IMetadataExchange” binding=”mexHttpBinding” address=”mex” />

</service>

After applied .Net 3.5 SP1, IIS returns 400 every time browse to follow URL in browser.

https://NLB_Virtual_Name.Organization.Company.Com/MyService/MyService.svc

 

Usually, 400 is rejected by HTTP.SYS due to the request header doesn’t compliant with the HTTP protocol. However, for this scenario, we see the 400 in IIS log instead of HTTP error log. This indicates the 400 status code should be set by the application instead of HTTP.SYS.

Then, we enabled WCF trace, and we got this error.

<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.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)

….

at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

</StackTrace>

<ExceptionString>System.ServiceModel.ProtocolException: There is a problem with the XML that was received from the network. See inner exception for more details. —&gt; System.Xml.XmlException: The body of the message cannot be read because it is empty.

   — End of inner exception stack trace —</ExceptionString>

 

For this service, there were 4 ChannelListeners created. When browsing to the .SVC file, the request was routed to item#1. This listener expects a POST request with body content; however, it was an HTTPS GET request which doesn’t have any body content. This is the reason why WCF returns the 400 response. In good scenario, the request is dispatched to item#4 instead.

#

URI

MessageVersion

Method

1

https://NLB_Virtual_Name.Organization.Company.Com/MyService/MyService.svc

soap12Addressing10

String.Empty

2

http://MachineName.Organization.Company.Com/MyService/MyService.svc/mex

soap12Addressing10

String.Empty

3

http://MachineName.Organization.Company.Com/MyService/MyService.svc

None

GET

4

https://MachineName.Organization.Company.Com/MyService/MyService.svc

None

GET

 

This was due to the logic how WCF resolve the URL and hostNameComparisonMode. By default, WCF looks for any results matched with https://*/MyService/MyService.svc. For this scenario, both item #1 and #4 matched. In case of this, WCF incorrectly selected the one which listening URI is longer.

Now, we are able to reproduce this issue very easily as long as we give an abosolute binding address which is longer than the host FQDN. For this case, it is basicHttpBinding, I believe this applies to all HTTP binding.

The workaround of this issue is to remove the absolute URI since we don’t need it for IIS hosted WCF services.

Wei from APGC DSI Team

Comments (1)

  1. shrikant says:

    where to remove absolute URI please

Skip to main content