我想用新的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)
尚未被调用。