ServiceStack [XmlSerializerFormat]兼容旧客户端的SOAP Web服务

时间:2013-10-17 16:40:22

标签: wcf soap servicestack servicestack-bsd

我想用新的ServiceStack服务替换WCF Web服务。 WCF服务使用basicHttpBinding,传统客户端使用HTTP POST通过SOAP调用它。我遇到的问题是旧版客户端使用[XmlSerializerFormat]而不是[DataContract],并且无法更改。我检查了客户端生成的SOAP信封,并通过我的新ServiceStack服务的元数据页面显示,并且没有发现请求中的任何关键不匹配。除了回复之外,它们看起来非常相似。 Service Stack的响应使用自定义命名空间。

以下是WCF服务的API,它与旧版客户端配合得很好。它有非常简单的API:只有两种方法。

[ServiceContract(Namespace = WebConstants.SoapNamespace)]
[XmlSerializerFormat]
public interface IMicexNewsWcf
{
    [OperationContract(Action = WebConstants.SoapNamespace + "PostNews")]
    [FaultContract(typeof(ExceptionDetail))]
    [PrincipalPermission(SecurityAction.Demand, Role = WebConstants.UserRole)]
    string PostNews (MarketNewsRaw[] st, string rynok);

    [OperationContract(Action = WebConstants.SoapNamespace + "SendMarkerUsingDB")]
    [FaultContract(typeof(ExceptionDetail))]
    [PrincipalPermission(SecurityAction.Demand, Role = WebConstants.UserRole)]
    void SendMarkerUsingDB (string id, string dt, string status, string problem);
}

[XmlSerializerFormat]
public sealed class MarketNewsRaw
{
    [DataMember(Order = 1)]
    public string SysTime {get; set;}
    [DataMember(Order = 2)]
    public string Urgency {get; set;}
    [DataMember(Order = 3)]
    public string FromUser {get; set;}
    [DataMember(Order = 4)]
    public string MsgTime {get; set;}
    [DataMember(Order = 5)]
    public string MsgText {get; set;}
}

服务实施:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public sealed class MicexNewsWcf: WcfServiceBase, IMicexNewsWcf
{
    public const string SrvName = "NewsListener";

    readonly IMicexNewsListenerService _listenerSrv;
    readonly IAbstractLogger _logger;

    public MicexNewsWcf (IAbstractLoggerFactory loggerFac, IMicexNewsListenerService listenerSrv): base(loggerFac.GetLogger(SrvName))
    {
        _listenerSrv = listenerSrv;
        _logger = loggerFac.GetLogger(SrvName);
    }

    public string PostNews (MarketNewsRaw[] st, string rynok)
    {           

      return "Ok";
    }

    public void SendMarkerUsingDB (string id, string dt, string status, string problem)
    {                           
    }
}

旧版客户端发送的SOAP XML示例:

<SOAP-ENV:Envelope xmlns:SOAPSDK1="http://www.w3.org/2001/XMLSchema" xmlns:SOAPSDK2="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAPSDK3="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body>
        <PostNews xmlns="http://xxx/">
            <st>
                <MarketNewsRaw>
                  <SysTime>17.10.2013 10:35:38</SysTime>
                  <Urgency>U</Urgency>
                  <FromUser>MZ000020069A</FromUser>
                  <MsgTime>10:35:38</MsgTime>
                  <MsgText>Some text</MsgText>
                </MarketNewsRaw>
                <MarketNewsRaw>
                  <SysTime>17.10.2013 11:21:26</SysTime>
                  <Urgency>U</Urgency>
                  <FromUser>MM0000101281</FromUser>
                  <MsgTime>11:21:27</MsgTime>
                  <MsgText>XXX 2</MsgText>
                <MarketNewsRaw>
            </st>
            <rynok>4</rynok>
        </PostNews>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我的WCF服务basicHttpBinding接受的精确SOAP。

要替换WCF服务,我实现了ServiceStack服务,如下所示。

[XmlSerializerFormat]
[Route("/MicexNews", "POST")]
public sealed class PostNews: IReturn<PostNewsResponse>
{
    [DataMember(Order = 1)]
    public MarketNewsRaw[] st;

    [DataMember(Order = 2)]
    public string rynok;


    public override string ToString ()
    {
        StringBuilder bld = new StringBuilder();
        if (st != null)
            foreach (var s in st)
            {
                if (bld.Length > 0)
                    bld.Append(", ");
                bld.AppendFormat("<{0}>", s.ToString());
            }
        return string.Format("st = [{0}], rynok = {1}", bld.ToString(), rynok);
    }
}

[XmlSerializerFormat]
public sealed class PostNewsResponse: IHasResponseStatus
{
    public PostNewsResponse ()
    {
        ResponseStatus = new ResponseStatus();
    }

    [DataMember(Order = 1)]
    public ResponseStatus ResponseStatus { get; set; }

    [DataMember(Order = 2)]
    public string Result {get; set; }
}

[XmlSerializerFormat]
[Route("/MicexNews", "POST")]
public sealed class SendMarkerUsingDB: IReturn<SendMarkerUsingDBResponse>
{
    [DataMember(Order = 1)]
    public string id {get; set;}
    [DataMember(Order = 2)]
    public string dt {get; set;}
    [DataMember(Order = 3)]
    public string status {get; set;}
    [DataMember(Order = 4)]
    public string problem {get; set;}

    public override string ToString ()
    {
        return string.Format("id = {0}, dt = {1}, status = {2}, problem = {3}", id, dt, status, problem);
    }
}

[XmlSerializerFormat]
public sealed class SendMarkerUsingDBResponse: IHasResponseStatus
{
    [DataMember(Order = 1)]
    public ResponseStatus ResponseStatus { get; set; }
}


public sealed class MicexNewsWebService: Service, IPost<PostNews>, IPost<SendMarkerUsingDB>
{
    public const string SrvName = "NewsListener";

    readonly IMicexNewsListenerService _listenerSrv;
    readonly IAbstractLogger _logger;

    public MicexNewsWebService (IAbstractLoggerFactory loggerFac, IMicexNewsListenerService listenerSrv)
    {
        _listenerSrv = listenerSrv;
        _logger = loggerFac.GetLogger(SrvName);
    }

    public object Post (PostNews req)
    {
        PostNewsResponse stat = new PostNewsResponse();
        stat.Result = "Ok";

        return stat;
    }

    public object Post (SendMarkerUsingDB request)
    {
        SendMarkerUsingDBResponse stat = new SendMarkerUsingDBResponse();           

        return stat;
    }
}

元数据页面显示了SOAP示例:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>

<PostNews xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xxx/">
  <rynok>String</rynok>
  <st>
    <MarketNewsRaw>
      <FromUser>String</FromUser>
      <MsgText>String</MsgText>
      <MsgTime>String</MsgTime>
      <SysTime>String</SysTime>
      <Urgency>String</Urgency>
    </MarketNewsRaw>
  </st>
</PostNews>

    </soap:Body>
</soap:Envelope>

回应:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>

<PostNewsResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xxx/">
  <ResponseStatus xmlns:d2p1="http://schemas.servicestack.net/types">
    <d2p1:ErrorCode>String</d2p1:ErrorCode>
    <d2p1:Message>String</d2p1:Message>
    <d2p1:StackTrace>String</d2p1:StackTrace>
    <d2p1:Errors>
      <d2p1:ResponseError>
        <d2p1:ErrorCode>String</d2p1:ErrorCode>
        <d2p1:FieldName>String</d2p1:FieldName>
        <d2p1:Message>String</d2p1:Message>
      </d2p1:ResponseError>
    </d2p1:Errors>
  </ResponseStatus>
  <Result>String</Result>
</PostNewsResponse>

    </soap:Body>
</soap:Envelope>

因此,我可以通过测试ServiceStack Json客户端调用ServiceStack服务,但是来自我的旧客户端的调用失败。

我如何调整ServiceStack以理解旧的RPC SOAP以及WCF,以及接口上指定的[XmlSerializerFormat]属性?

传统客户端报告400 Bad Request和我的ServiceStack服务甚至没有被调用。我的意思是,方法public object Post (PostNews req)尚未被调用。

0 个答案:

没有答案