如何将使用键的XML反序列化为对象

时间:2019-02-20 16:57:34

标签: c# xml xml-parsing xmlserializer asp.net-core-2.1

我有一个ASP.NET core 2.1 MVC项目,我正在从Serlilog MSSqlServr接收器检索数据,该数据存储在Properties字段中作为XML数据类型。我想将该数据反序列化到视图模型中,以便可以在视图中将各个元素显示为数据。

这是数据库“日志”表中“属性”字段中XML的示例。

form-group

我为解码设置了一个类,如下所示:

userRepository.find({
  where: [
    {
      email: 'giberish@gmail.com',
    },
    {
      username: 'thisismyusername',
    },
  ]
});

在我的控制器中,我有以下代码;

  errmsg:
   'Error getting filter : Error getting filter BSON field from doc = [{find user} {filter [[{email giberish@gmail.com}] [{username thisismyusername}]]} {returnKey false} {showRecordId false} {$clusterTime [{clusterTime 6660127540193001473} {signature [{hash [184 253 193 112 111 39 205 239 38 92 178 205 149 85 131 136 252 114 180 30]} {keyId 6637077103550398465}]}]}] : not bson []interface {} [[{email craftball@gmail.com}] [{username thisismyusername}]]\n\tat erh/mongonet/bsonutil.go:122\n\tat 10gen/atlasproxy/bson_util.go:32\n\tat 10gen/atlasproxy/commands_security.go:521\n\tat 10gen/atlasproxy/commands.go:653\n\tat 10gen/atlasproxy/commands.go:563\n\tat 10gen/atlasproxy/session_proxy.go:256\n\tat 10gen/atlasproxy/session_proxy.go:702\n\tat 10gen/atlasproxy/session_proxy.go:526\n\tat erh/mongonet/proxy.go:209\n\tat erh/mongonet/proxy.go:104\n\tat erh/mongonet/session.go:82\n\tat src/runtime/asm_amd64.s:2361',
code: 8000,
codeName: 'AtlasError',
name: 'MongoError'

但是logProperties变量不包含任何内容,因此我假设我在LogProperties类中具有错误的XML属性。

我花了很多时间寻找解决方案,并在输入此问题时查看了所有相关文章,但是我找不到XML使用“ property key =“或如何处理XML的示例。带有“ key =“属性属性(如果这是正确的术语)

有什么想法吗?

[UPDATE 2/21/19]

我最终使用了@jdweng建议,因为它最简单,并且给了我我想要的东西。

我创建了2个班级(因为我想将班级文件分开作为个人偏好)。这些课程在下面;

<properties>
  <property key="EventId">
    <structure type="">
      <property key="Id">404</property>
    </structure>
  </property>
  <property key="ActionId">0592d9e8-f4fd-459f-96b3-2b787d01a754</property>
  <property key="ActionName">API.Controllers.CompletionsController.GetCompletion (PS.API)</property>
  <property key="RequestId">0HLJ2IL5A9:00000001</property>
  <property key="RequestPath">/api/completions/0</property>
  <property key="CorrelationId" />
  <property key="ConnectionId">0HLJ2IL59</property>
  <property key="MachineName">RD0003FF1</property>
  <property key="ThreadId">117</property>
</properties>

using System.Xml.Serialization;

namespace PS.Models.ApiLogs
{
    [XmlRoot("properties")]
    public class LogProperties
    {

        [XmlElement("SourceContext")]
        public string SourceContext { get; set; }

        [XmlElement("ActionId")]
        public string ActionId { get; set; }

        [XmlElement("ActionName")]
        public string ActionName { get; set; }

        [XmlElement("RequestId")]
        public string RequestId { get; set; }

        [XmlElement("RequestPath")]
        public string RequestPath { get; set; }

        [XmlElement("CorrelationId")]
        public string CorrelationId { get; set; }

        [XmlElement("ConnectionId")]
        public string ConnectionId { get; set; }

        [XmlElement("MachineName")]
        public string MachineName { get; set; }

        [XmlElement("ThreadId")]
        public string ThreadId { get; set; }

    }
}

然后在我的控制器中,我对Detail方法有以下要求;

        var serializer = new XmlSerializer(typeof(LogProperties));

        LogProperties logProperties;

        using (TextReader reader = new StringReader(log.Properties))
        {
            logProperties = (LogProperties)serializer.Deserialize(reader);
        }

我的DetailLogWithPropertiesViewModel在下面;

using System.Collections.Generic;
using System.Xml.Serialization;

namespace PS.Models.ApiLogs
{
    [XmlRoot("properties")]
    public class LogProperties
    {
        [XmlElement("property")]
        public List<LogProperty> Property { get; set; }

    }
}

下面是我的Detail.cshtml的相关部分;

using System.Xml.Serialization;

namespace PS.Models.ApiLogs
{
    [XmlRoot("property")]
    public class LogProperty
    {
        [XmlAttribute("key")]
        public string Key { get; set; }
        [XmlText]
        public string Value { get; set; }
    }
}

由Serilog生成并存储在MS SQL数据库中的XML具有可变数量的属性,我现在理解这些属性表示为键/值对。因此,该方法使我可以确保所有提供的属性都显示在网站的日志查看器中。

3 个答案:

答案 0 :(得分:1)

尝试以下操作:

    [XmlRoot("properties")]
    public class LogProperties
    {

        [XmlElement("property")]
        public List<LogProperty> property { get; set; }

    }
    [XmlRoot("property")]
    public class LogProperty
    {
        [XmlAttribute("key")]
        public string key { get; set; }
        [XmlText]
        public string value { get; set; }
    }

答案 1 :(得分:0)

1)将XML复制到剪贴板...
2)...打开Visual Studio并创建一个空的CS文件...
3)...转到“编辑”>“选择性粘贴”>“ XML到类”(可能需要安装ASP.NET Web开发)...
3)...将产生以下代码:

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class properties
{

    private propertiesProperty[] propertyField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("property")]
    public propertiesProperty[] property
    {
        get
        {
            return this.propertyField;
        }
        set
        {
            this.propertyField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class propertiesProperty
{

    private propertiesPropertyStructure structureField;

    private string[] textField;

    private string keyField;

    /// <remarks/>
    public propertiesPropertyStructure structure
    {
        get
        {
            return this.structureField;
        }
        set
        {
            this.structureField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string[] Text
    {
        get
        {
            return this.textField;
        }
        set
        {
            this.textField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string key
    {
        get
        {
            return this.keyField;
        }
        set
        {
            this.keyField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class propertiesPropertyStructure
{

    private propertiesPropertyStructureProperty propertyField;

    private string typeField;

    /// <remarks/>
    public propertiesPropertyStructureProperty property
    {
        get
        {
            return this.propertyField;
        }
        set
        {
            this.propertyField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class propertiesPropertyStructureProperty
{

    private string keyField;

    private ushort valueField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string key
    {
        get
        {
            return this.keyField;
        }
        set
        {
            this.keyField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public ushort Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            this.valueField = value;
        }
    }
}

4)是,很多代码o_O。使用XmlDeserializer(typeof(properties))

答案 2 :(得分:0)

如果您制作LogProperties类的示例实例,并像这样序列化它:

var serializer = new XmlSerializer(typeof(LogProperties));

LogProperties logProperties = new LogProperties() 
{ 
    SourceContext = "MySourceContext",
    ActionId = "MyActionId",
    ActionName = "MyActionName"
};

StringBuilder sb = new StringBuilder();
using (StringWriter writer = new StringWriter(sb))
{
    serializer.Serialize(writer, logProperties);
}

Console.WriteLine(sb.ToString());

这是您得到的:

<?xml version="1.0" encoding="utf-16"?>
<properties xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SourceContext>MySourceContext</SourceContext>
  <ActionId>MyActionId</ActionId>
  <ActionName>MyActionName</ActionName>
</properties>

因此您拥有的类与您拥有的XML不太匹配。尝试双向进行序列化总是很有用的。

下面是一种将拥有的XML序列化为拥有的类的方法(将对象模型和持久性格式清楚地分开)。它使用System.Xml.Linq命名空间中的XDocument类。

// Must escape all quotes !
string xmlSample = @"
<properties>
    <property key=""EventId"">
        <structure type = """">
            <property key=""Id"">404</property>
        </structure>
    </property>
    <property key=""ActionId""> 0592d9e8 - f4fd - 459f - 96b3 - 2b787d01a754</property>
    <property key=""ActionName""> API.Controllers.CompletionsController.GetCompletion(PS.API)</property>
    <property key=""RequestId""> 0HLJ2IL5A9: 00000001</property>
    <property key=""RequestPath"">/api/completions/0</property>
    <property key=""CorrelationId"" />
    <property key=""ConnectionId"">0HLJ2IL59</property>
    <property key=""MachineName"">RD0003FF1</property>
    <property key=""ThreadId"">117</property>
</properties>";

StringReader reader = new StringReader(xmlSample);
XDocument xdoc = XDocument.Parse(xmlSample);

LogProperties log = new LogProperties();
foreach (XElement prop in xdoc.Root.Elements())
{
    switch (prop.Attribute("key").Value)
    {
    case "ActionId" : log.ActionId = prop.Value; break;
    case "ActionName" : log.ActionName = prop.Value; break;

    // and so on

    }
}

请注意,使用这种方法:

  • 您不需要类中的XML属性
  • 您不需要调整类以适合XML(或者相反)
  • 您可以添加自己的LogProperties类的自定义初始化(不再需要默认的构造函数)
  • 您可以添加自己的自定义错误处理