可以接受 content-type 的 WCF WebInvoke:text/plain?

WCF WebInvoke which can accept content-type: text/plain?

我正在编写 WCF REST 服务以使用我的 WCF REST 服务接收 AWS SNS 通知消息。

但是,WCF REST 仅支持 XML 和 JSON,但由于遗留原因,Amazon SNS 根据 Content-Type: text/plain; charset=UTF-8 header 发布其通知 Amazon documentation:

POST / HTTP/1.1
Content-Type: text/plain; charset=UTF-8
// ...

{
  "Type" : "Notification",
  // ...
  "UnsubscribeURL" : "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&..."
}

当我使用像亚马逊这样的“text/plain”内容类型调用我的服务时,出现一个错误:

Request Error.

The server encountered an error processing the request. The exception message is 'The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml'; 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details.'. See server logs for more details.

我当前的代码:

public interface MyServiceInterface
{
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "/AmazonIPChanges")]
    Task AmazonIPChanges(SNSNotificationMessage data);
}

[DataContract]
public class SNSNotificationMessage
{
    [DataMember]
    public string Type { get; set; }
    // ...
    [DataMember]
    public string UnsubscribeURL { get; set; }
} 

DataContract 映射到 Amazon SNS 消息。当我用 content-type “application/json” 执行 POST 时,此代码有效,但如何让它接受亚马逊的 text/plain content-type?

如错误消息所示,您可以通过创建和应用自定义 WebContentTypeMapper 来解决此问题。它应该是这样的:

namespace Whosebug36216464
{
    public class RawContentTypeMapper : WebContentTypeMapper
    {
        public override WebContentFormat GetMessageFormatForContentType(string contentType)
        {
            switch (contentType.ToLowerInvariant())
            {
                case "text/plain":
                case "application/json":
                    return WebContentFormat.Json;
                case "application/xml":
                    return WebContentFormat.Xml;
                default:
                    return WebContentFormat.Default;
            }
        }
    }
}

这个解释请求的内容类型,returns 适当的 WebContentFormat 枚举成员。

然后您可以将其以自定义绑定的形式应用于您的服务:

<system.serviceModel>
    <bindings>
        <customBinding>
            <binding name="textPlainToApplicationJson">
                <webMessageEncoding webContentTypeMapperType="Whosebug36216464.RawContentTypeMapper, Whosebug36216464, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
                <httpTransport manualAddressing="true" />
            </binding>
        </customBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="debugServiceBehavior">
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
            <behavior name="restEndpointBehavior">
                <webHttp />
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <services>
        <service
          name="Whosebug36216464.Service1"
          behaviorConfiguration="debugServiceBehavior">
            <host>
                <baseAddresses>
                    <add baseAddress="http://localhost:65393/"/>
                </baseAddresses>
            </host>
            <endpoint address=""
                  binding="customBinding"
                  contract="Whosebug36216464.IService1"
                  behaviorConfiguration="restEndpointBehavior"
                  bindingConfiguration="textPlainToApplicationJson"/>        
        </service>
    </services>
</system.serviceModel>

相关部分是配置自定义映射器的 <customBinding> 元素,以及应用它的 servcices/service/endpoint/bindingConfiguration 属性。