我想用新的 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)
还没有被调用。