【问题标题】:Parameter is null depending on xml format参数为空,具体取决于 xml 格式
【发布时间】:2015-12-26 01:00:45
【问题描述】:

我有这门课:

[XmlRoot(ElementName = "order")]
public class Order
{
    [XmlElement(ElementName= "buyer-accepts-marketing")]
    public bool BuyerAcceptsMarketing { get; set; }

    [XmlElement(ElementName= "closed-at")]
    public DateTime? ClosedAt { get; set; }
}

这个简单的控制器和我用来测试请求的这种方法:

public class OrdersController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Post([FromBody]Order order)
    {
        return Request.CreateResponse(HttpStatusCode.OK);
    }
}

当我在本地运行服务并使用 Fiddler 将此 xml 发布到服务时: <?xml version="1.0" encoding="UTF-8"?> <order> <buyer-accepts-marketing type="boolean">false</buyer-accepts-marketing> </order> 我在控制器的 Post 方法中收到参数,一切正常。 但是,如果我发布带有第二个属性的 xml:

<?xml version="1.0" encoding="UTF-8"?> <order> <buyer-accepts-marketing type="boolean">false</buyer-accepts-marketing> <closed-at type="datetime" nil="true"></closed-at> </order>

参数order在Controller的方法中到达null。

我可能在 xml 或类的“映射”中做错了,但我看不到它是什么。

【问题讨论】:

  • 我可以看到你没有在 xml 中发送关闭时间。datetime 的值在哪里?

标签: c# asp.net xml web-services asp.net-web-api2


【解决方案1】:

您已将nil 属性放置在默认命名空间中。您需要将其放在 "http://www.w3.org/2001/XMLSchema-instance" 命名空间中。执行此操作的常规方法是将其放在带有 xsi 前缀的根元素中:

<?xml version="1.0" encoding="UTF-8"?>
<order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
  <buyer-accepts-marketing type="boolean">false</buyer-accepts-marketing>
  <closed-at type="datetime" xsi:nil="true"></closed-at>
</order>

但将它放在"closed-at" 元素本身上在语义上是相同的:

<?xml version="1.0" encoding="UTF-8"?>
<order >
  <buyer-accepts-marketing type="boolean">false</buyer-accepts-marketing>
  <closed-at xmlns:i="http://www.w3.org/2001/XMLSchema-instance" type="datetime" i:nil="true"></closed-at>
</order>

由于DateTime? ClosedAt 不为空(因为它没有正确的xsi:nil="true" 属性)而且也不能反序列化为DateTime(因为值为空),所以XmlSerializer 会混淆并抛出一个例外。

更新

如果您无法将 XML 更改为包含 standard representation for a null DateTime,则需要实现代理属性以手动进行转换。由于您没有在问题中指定是否需要反序列化和反序列化,因此以下两者都可以:

[XmlRoot(ElementName = "order")]
public class Order
{
    [XmlElement(ElementName = "buyer-accepts-marketing")]
    public bool BuyerAcceptsMarketing { get; set; }

    [XmlIgnore]
    public DateTime? ClosedAt { get; set; }

    [XmlElement("closed-at")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public XmlDateTimeWrapper XmlDateTime
    {
        get
        {
            return ClosedAt;
        }
        set
        {
            ClosedAt = value;
        }
    }
}

public class XmlDateTimeWrapper
{
    public static implicit operator DateTime?(XmlDateTimeWrapper wrapper) { return wrapper == null ? null : wrapper.DateTime; }

    public static implicit operator XmlDateTimeWrapper(DateTime? dateTime) { return new XmlDateTimeWrapper { DateTime = dateTime }; }

    [XmlIgnore]
    public DateTime? DateTime { get; set; }

    [XmlText]
    public string DateTimeString
    {
        get
        {
            if (DateTime == null)
                return string.Empty;
            return XmlConvert.ToString(DateTime.Value, XmlDateTimeSerializationMode.Utc);
        }
        set
        {
            if (String.IsNullOrWhiteSpace(value))
                DateTime = null;
            else
                DateTime = XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc);
        }
    }

    [XmlAttribute("type")]
    public string Type { get { return "datetime"; } set { /* Do nothing */ } }

    [XmlAttribute("nil")]
    public bool Nil { get { return DateTime == null; } set { /* Do nothing */ } }
}

如果您从不需要序列化回来,您可以使用字符串值代理属性:

[XmlRoot(ElementName = "order")]
public class Order
{
    [XmlElement(ElementName = "buyer-accepts-marketing")]
    public bool BuyerAcceptsMarketing { get; set; }

    [XmlIgnore]
    public DateTime? ClosedAt { get; set; }

    [XmlElement("closed-at")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public string XmlDateTime
    {
        get
        {
            return ClosedAt == null ? null : XmlConvert.ToString(ClosedAt.Value, XmlDateTimeSerializationMode.Utc);
        }
        set
        {
            if (String.IsNullOrWhiteSpace(value))
                ClosedAt = null;
            else
                ClosedAt = XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc);
        }
    }
}

【讨论】:

  • 感谢您的回答!问题是我无权更改此 xml。它将采用这种格式(带有更多节点)。在这种情况下我该怎么办?
  • @gabsferreira - 你能分享一下这些额外节点的样子吗?是否提供了XSD schema
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多