Summary
I have a WCF backend service running in an Azure app service, and I'm developing a proxy which will use the same interface but manipulate some messages for compatibility with a client's system. I know this is a bit vague, but the details aren't important.
The problem is that when the proxy, running in IIS Express from Visual Studio 17, calls the backend it is doing so incorrectly, and the backend rejects the request. (Curiously the precise nature of the rejection differs between the real service and the minimal reproducible test case I've created for this post, but the difference is late enough that I don't believe it to be relevant).
By adding trace listeners to System.Net I can observe that the call made by the proxy to the backend has a body in JSON but headers which claim that it's XML:
System.Net Verbose: 0 : [4140] Data from ConnectStream#29742526::Write
System.Net Verbose: 0 : [4140] 00000000 : 7B 22 42 61 72 22 3A 22-42 2D 50 72 6F 78 69 65 : {"Bar":"B-Proxie
System.Net Verbose: 0 : [4140] 00000010 : 64 22 2C 22 46 6F 6F 22-3A 22 41 22 7D : d","Foo":"A"}
System.Net Verbose: 0 : [4140] Exiting ConnectStream#29742526::Write()
System.Net Verbose: 0 : [4140] Entering ConnectStream#29742526::Close()
System.Net Verbose: 0 : [4140] Exiting ConnectStream#29742526::Close()
System.Net Verbose: 0 : [4140] Entering HttpWebRequest#45658036::GetResponse()
System.Net Information: 0 : [4140] HttpWebRequest#45658036 - Request: POST /DemoService.svc/DoTheThing HTTP/1.1
System.Net Information: 0 : [4140] ConnectStream#29742526 - Sending headers
{
Content-Type: application/xml; charset=utf-8
Host: wcfproxydemo.azurewebsites.net
Content-Length: 29
Expect: 100-continue
Accept-Encoding: gzip, deflate
Connection: Close
}.
Can I change some configuration to get it to send JSON with the correct Content-Type header? I'd prefer not to have to switch everything over to XML.
Details
My minimal reproducible test case is available on Github. The only thing I've elided there is the publish profile to push the backend to Azure.
The various projects share an interface project, and there's no auto-generated service reference. (That might be a possible way forward, but it seems rather heavy-weight, so I'd prefer a config-based solution). The WCF config for the three components is
Backend
<system.serviceModel>
<bindings>
<customBinding>
<binding name="rest-https-nokeepalive">
<webMessageEncoding />
<httpsTransport manualAddressing="true" allowCookies="false" keepAliveEnabled="false" maxBufferSize="10000000" maxReceivedMessageSize="10000000" maxBufferPoolSize="10000000" />
</binding>
</customBinding>
</bindings>
<services>
<service name="Backend.DemoService" behaviorConfiguration="ServiceBehaviour">
<endpoint binding="customBinding" bindingConfiguration="rest-https-nokeepalive" contract="Interface.IDemoService" behaviorConfiguration="web" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Proxy
<system.serviceModel>
<bindings>
<customBinding>
<binding name="rest-https-nokeepalive">
<webMessageEncoding />
<httpsTransport manualAddressing="true" allowCookies="false" keepAliveEnabled="false" maxBufferSize="10000000" maxReceivedMessageSize="10000000" maxBufferPoolSize="10000000" />
</binding>
</customBinding>
</bindings>
<services>
<service name="Proxy.DemoService" behaviorConfiguration="ServiceBehaviour">
<endpoint binding="customBinding" bindingConfiguration="rest-https-nokeepalive" contract="Interface.IDemoService" behaviorConfiguration="web" />
</service>
</services>
<client>
<endpoint name="Backend" address="https://wcfproxydemo.azurewebsites.net/DemoService.svc" binding="customBinding" bindingConfiguration="rest-https-nokeepalive" contract="Interface.IDemoService" behaviorConfiguration="web" />
</client>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true" />
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" maxMessagesToLog="3000" maxSizeOfMessageToLog="2000" />
</diagnostics>
</system.serviceModel>
Test frontend
<system.serviceModel>
<bindings>
<customBinding>
<binding name="rest-https-nokeepalive">
<webMessageEncoding />
<httpsTransport manualAddressing="true" allowCookies="false" keepAliveEnabled="false" maxBufferSize="10000000" maxReceivedMessageSize="10000000" maxBufferPoolSize="10000000" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint name="Direct" address="https://wcfproxydemo.azurewebsites.net/DemoService.svc" binding="customBinding" bindingConfiguration="rest-https-nokeepalive" contract="Interface.IDemoService" behaviorConfiguration="web" />
<endpoint name="Proxied" address="https://localhost:44388/DemoService.svc" binding="customBinding" bindingConfiguration="rest-https-nokeepalive" contract="Interface.IDemoService" behaviorConfiguration="web" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" maxMessagesToLog="3000" maxSizeOfMessageToLog="2000"/>
</diagnostics>
</system.serviceModel>
A direct connection from the frontend to the backend works fine. A proxied connection fails because the backend isn't happy with the request it receives from the proxy, for obvious reasons.