2

我想用新的 ServiceStack 服务替换 WCF Web 服务。WCF 服务使用 basicHttpBinding,它由旧客户端通过 SOAP 使用 HTTP POST 调用。我面临的问题是旧客户端使用[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.

为了替换 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)还没有被调用。

4

0 回答 0