【问题标题】:How to include empty xml elements in SOAP request using WCF?如何使用 WCF 在 SOAP 请求中包含空 xml 元素?
【发布时间】:2017-05-18 07:27:49
【问题描述】:

我必须使用Java 网络服务。服务方法的签名是

public bool UpsertEmployee(Employee employe);

问题是在生成SOAP 时,对于具有空值的属性,请求中不包含对应的XML 元素。结果是:

...
<Employee>
  <id>1</id>
  <firstName>Jhonny</firstName>
</Employee>

我想成为:

...
<Employee>
  <id>1</id>
  <firstName>Jhonny</firstName>
  <lastName/>
</Employee>

有没有办法做到这一点?

我可以在方法调用之前设置属性吗?

var client= new EmployeeServiceClient();;
// Can I do something here to accoplish my goal?    
client.UpsertEmployee(new Employee{
    id = "1",
    firstname = "Jhonny"
});

生成的Employee类代码是

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.36366")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "urn:mve.go.all.mdg.vendor")]
public partial class Employee : object, System.ComponentModel.INotifyPropertyChanged
{

    private string idField;

    private string firstNameField;

    private string lastNameField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
    public string id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
            this.RaisePropertyChanged("id");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
    public string firstName
    {
        get
        {
            return this.firstNameField;
        }
        set
        {
            this.firstNameField = value;
            this.RaisePropertyChanged("firstName");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 3)]
    public string lastName
    {
        get
        {
            return this.lastNameField;
        }
        set
        {
            this.lastNameField = value;
            this.RaisePropertyChanged("lastName");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null))
        {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

我无法修改文件代码,因为将来可能需要更新服务参考。

【问题讨论】:

  • 可能是Employee定义的结果。 Employee 可能是您的自定义类,因此应将其定义为DataContract,并将其属性定义为DataMembers。在DataMember 中,有一个名为EmitCustomValue 的设置(默认为true)。它控制 SOAP 中是否包含空值。有关更多信息,请查看msdn.microsoft.com/en-us/library/…。查看Employee 类定义并验证EmitDefaultValue 是否 设置为false
  • 服务写在Java,我检查了文件Reference.cs(通过在服务类名称上按f12)并且没有DataContract 属性,而是所有属性都有XmlElementAttribute 属性,我无法修改文件代码,因为将来可能需要更新服务引用。
  • 需要查看Employee 类以确保,但设置lastName = "" 应该可以工作。两个 c# xml 序列化器都将空字符串序列化为空元素,默认情况下完全跳过空字符串。
  • 我已经更新了我的问题。我为Employee 类添加了自动生成的代码。在添加对Java web 服务的引用后生成的类。

标签: c# xml web-services wcf


【解决方案1】:

您的课程标有XmlSerializer attributes,因此您似乎正在使用该序列化程序。

您的问题是lastName 属性是null。如Xsi:nil Attribute Binding Support中所述:

当将对象序列化为 XML 文档时:如果 XmlSerializer 类遇到对应于 XML 元素的对象的空引用,它要么生成一个指定 xsi:nil="true" 的元素,要么完全忽略该元素,具体取决于是否nillable="true" 设置适用。

因此,默认情况下,当 lastName 为 null 时,不会发出任何元素。如果你设置[XmlElementAttribute(IsNullable = true)] 你会得到

<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <id>1</id>
  <firstName>Jhonny</firstName>
  <lastName xsi:nil="true" />
</Employee>

不是您想要的(无论如何您都无法更改自动生成的代码)。

相反,您需要将lastName 初始化为空字符串:

var employee = new Employee
{
    id = "1",
    firstName = "Jhonny",
    lastName = "",
};

然后会生成以下XML:

<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <id>1</id>
  <firstName>Jhonny</firstName>
  <lastName />
</Employee>

或者,由于自动生成的代码没有默认构造函数,您可以自己在单独的partial class 代码文件中添加一个。由于它独立于自动生成的代码文件,因此在您重新生成生成的代码时不会被覆盖:

public partial class Employee
{
    public Employee()
    {
        this.firstName = this.lastName = this.id = "";
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-26
    • 2023-03-03
    • 2018-12-23
    • 2017-10-06
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多