WCF Service - calling a client to access rest usin

2019-09-09 15:00发布

问题:

i have an issue (of which i've been pulling my hair out for a number of days) whereby I'm attempting to use a WCF service to call another RESTful service.

however, when tracing this through it fails to put the correct json content type on the message.

example of call in client (this is within a WCF service which calls the code)

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior()]
public partial class MyRestServiceClient : System.ServiceModel.ClientBase<IMyRestService>, IMyRestService
{
    [WebInvoke(Method = "POST", UriTemplate = "/MyService/ReferenceTypes.json", RequestFormat = WebMessageFormat.Json)]
    public MyServiceLists GetReferenceTypes()
    {
        try
        {
            return base.Channel.GetReferenceTypes();
        }
        catch (Exception e)
        {
            throw e; //throws exception here - method not allowed 
        }
    }
}

Instead of putting content type of application/json it places application/xml instead to the call. this was worked out from the activity tracing placed on the WCF service doing the call. example of the "message sent" info from Activity log:

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>262164</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2012-03-05T12:26:52.8913972Z" />
<Source Name="System.ServiceModel" />
<Correlation ActivityID="{7759c13c-972d-46a2-8048-2dcaf1c066bf}" />
<Execution ProcessName="aspnet_wp" ProcessID="2408" ThreadID="11" />
<Channel />
<Computer>Z1020734</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Information">
<TraceIdentifier>http://msdn.microsoft.com/en-GB/library/System.ServiceModel.Channels.MessageSent.aspx</TraceIdentifier>
<Description>Sent a message over a channel.</Description>
<AppDomain>/LM/w3svc/1/ROOT/My.Services-2-129754240054859056</AppDomain>
<Source>System.ServiceModel.Channels.HttpOutput+WebRequestHttpOutput/18905726</Source>
<ExtendedData xmlns="http://schemas.microsoft.com/2006/08/ServiceModel/MessageTraceRecord">
<MessageProperties>
**<Encoder>application/xml; charset=utf-8</Encoder>**
<AllowOutputBatching>False</AllowOutputBatching>
<Via>http://mymachine/My.services.stub.REST/</Via>
</MessageProperties>
<MessageHeaders></MessageHeaders>
</ExtendedData>
</TraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>

I have used a webHttpBinding for the client, then i've also tried the custom binding equivalent with a custom web content type mapper that forces a Json content type to no avail.

the client end point is pointing to a Restful service (using the Rest 40 template) on the same machine. see below for web.config of the WCf service that is trying to call the Rest endpoint:

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
  </connectionStrings>
  <appSettings>
  </appSettings>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  <system.serviceModel>
    <serviceHostingEnvironment  multipleSiteBindingsEnabled="true"/>
    <services>
      <service name="My.Services.MyService" behaviorConfiguration="My.Services.MyServiceBehavior" >
        <endpoint address="" binding="customBinding" bindingConfiguration="CustomBinding_IMyService" contract="My.Common.ServiceContracts.IMyService"/>
       </service>
      <service name="My.Services.SomeOtherService" behaviorConfiguration="My.Services.SomeOtherBehavior" >
        <endpoint address="" binding="customBinding"  bindingConfiguration="customBinding_ISomeOtherService" contract="My.Common.ServiceContracts.ISomeOtherService"/>
      </service>
    </services>
    <bindings>
      <webHttpBinding>
        <binding name="webHttpCustomBinding">
          <security mode="TransportCredentialOnly">
            <transport proxyCredentialType="None" clientCredentialType="Windows">
            </transport>
          </security>
        </binding>
      </webHttpBinding>

      <customBinding>
        <binding name ="CustomBinding_IIMyRestService">
           <webMessageEncoding webContentTypeMapperType="My.Common.ServiceModel.JsonContentTypeMapper, My.Common" ></webMessageEncoding>
          <httpTransport  authenticationScheme="Negotiate" ></httpTransport>
         </binding>
        <binding name="CustomBinding_IMyService">
          <textMessageEncoding messageVersion="Soap12" />
          <httpTransport maxBufferPoolSize="1000000" maxReceivedMessageSize="1000000"
            authenticationScheme="Negotiate" maxBufferSize="1000000"   />
        </binding>
        <binding name="customBinding_ISomeOtherService">
          <textMessageEncoding messageVersion="Soap12" />
          <httpTransport  />
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="http://MyMachine/My.services.stub.REST/" binding="customBinding" bindingConfiguration="CustomBinding_IMyRestService" name="RestService" contract="My.Common.ServiceContracts.IIMyRestService" behaviorConfiguration="webhttp"/>
 </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="webhttp">
        </behavior>
 </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="My.Services.MyServiceBehavior">
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
        <behavior name="My.Services.SomeOtherServiceBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <system.net>
    <defaultProxy useDefaultCredentials="true"/>
  </system.net>
 <system.diagnostics>
    <trace autoflush="true"/>
    <sources>
      <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
        <listeners>
          <add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\temp\my.Services.svclog"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics> 
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
</configuration>

Note: a console app i've written with the same function and config does work correctly, and gives the correct content type.

Any help you can give is appreciated.

回答1:

Not sure if you have gotten this resolved yet, but I ran into the same issue.
When calling a service from within an existing service call, you need to wrap the new call in a new OperationContextScope.

You can see the details here: WCF Rest Client sending incorrect content-type