【问题标题】:ServiceStack trying to bind private fields classes generated via service reference instead of public propertiesServiceStack 试图绑定通过服务引用而不是公共属性生成的私有字段类
【发布时间】:2019-04-19 13:06:46
【问题描述】:

我正在尝试使用 SOAP 通过 http POST 请求向我发送消息的远程服务。我使用集成在 Visual Studio 中的选项“添加服务引用”生成了服务 DTO。

这是一个自动生成的类的示例:

[Route("/test", "POST")]
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.2152")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, 
Namespace="http://www.reservationassistant.com/Booking/Types")]
public partial class UpdateBookingRequest
{

private Booking bookingField;

private string resortIdField;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=0)]
public Booking Booking
{
    get
    {
        return this.bookingField;
    }
    set
    {
        this.bookingField = value;
    }
}

当我创建我的 ServiceInterface 方法并运行我的服务时,进入元数据页面我会得到这个示例 SOAP 消息

<UpdateBookingRequest>
  <bookingField>
         ....
  <bookingField>
<UpdateBookingRequest>

这是我的服务接口类中的代码:

UpdateBookingResponse Post(UpdateBookingRequest request)
{
    // do stuff with request
    return null;
}

正如您可能通过自动生成的类所暗示的那样,我收到的消息将具有与生成的 DTO 中的公共属性相同的标记名称。然而,这永远不可能,因为出于某种原因,ServiceStack 试图将传入的 XML 消息元素绑定到 DTO 的私有字段(由我的服务的元数据页面生成的示例 SOAP 消息 - 请注意“预订”之后的“字段”后缀”)。如何使传入消息绑定到公共属性而不是私有字段?

【问题讨论】:

    标签: c# xml soap servicestack


    【解决方案1】:

    首先,如果您想要类型化 C# 服务,我强烈建议您使用C# Add ServiceStack Reference 中更具弹性、通用性、更简洁和更快的替代方案。 SOAP 是一个 slow, fragile and bloated serialization format,只应考虑用于旧版集成。

    默认情况下,ServiceStack 使用 .NET XML DataContract Serializer 进行 XML 或 SOAP 序列化,因此行为取决于 .NET 的 XML DataContractSerializer 实现。

    为了处理 SOAP,它使用 WCF 的通用 Message 类,该类默认使用 DataContractSerializer,但您可以切换到使用 XmlSerializer 实现填充 WCF 的 Message,方法是在请求和响应 DTO 上添加 [XmlSerializerFormat] attribute

    您可以请求 .NET 的 WCF svcutil 使用 /serializer 命令行开关强制生成 DataContract 或 XmlSerializer 类,例如:

    svcutil endpoint.wsdl /serializer:DataContractSerializer
    svcutil endpoint.wsdl /serializer:XmlSerializer
    

    覆盖 ContentTypes

    您可以注册custom Content Type 来覆盖用于 XML 请求的 Xml 序列化,例如您可以覆盖它以使用 XmlSerializer 实现来处理 XML 请求,例如:

    ContentTypes.Register(MimeTypes.Xml,
        (req, dto, stream) => {
            using (var xw = XmlWriter.Create(stream))
            {
                var ser = new XmlSerializerWrapper(dto.GetType());
                ser.WriteObject(xw, dto);
            }
        },
        (type, stream) => {
            using (var reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas()))
            {
                var serializer = new System.Xml.Serialization.XmlSerializer(type);
                return serializer.Deserialize(reader);
            }                    
        });
    

    SOAP 请求的元数据预览

    当您从元数据预览中推断行为时,请注意预览不是使用 WCF Serializer for SOAP 请求生成的,请求正文是使用 DataContraceSerializer 生成的,因此如果使用 XmlSerializer,它不会反映相同的输出在 WCF 消息中实现。

    【讨论】:

    • 有什么办法可以 1.) 覆盖 SS 用来作为 XMLSerializer 的序列化程序,或者 2.) 如果没有,有没有办法用 DataContractSerializer 属性自动标记生成文件的每个字段
    • @Play4u 我已经用更多信息更新了我的答案,请注意元数据预览使用 XML DataContractSerializer 作为其主体,并且不会显示使用 XmlSerializer impls 的 WCF 请求的真实输出。
    猜你喜欢
    • 2017-12-09
    • 1970-01-01
    • 2018-05-09
    • 2012-04-30
    • 2017-04-02
    • 1970-01-01
    • 2016-01-25
    • 2018-07-17
    • 2014-07-22
    相关资源
    最近更新 更多