自定义Json序列化类

Din*_*uja 21 c# json json.net

我的代码结构如下.

public class Stats
{
        public string URL { get; set; }
        public string Status { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public int Length { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

 public class UrlStats
 {
        public string URL { get; set; }
        public int TotalPagesFound { get; set; }
        public List<Stats> TotalPages { get; set; }
        public int TotalTitleTags { get; set; }
        public List<Stats> TotalTitles { get; set; }
        public int NoDuplicateTitleTags { get; set; }
        public List<Stats> DuplicateTitles { get; set; }
        public int NoOverlengthTitleTags { get; set; }
        public List<Stats> OverlengthTitles { get; set; }
 }
Run Code Online (Sandbox Code Playgroud)

基本上我正在扫描网站上的标题,如标题标签,重复标题等.

我正在使用JQuery并对web服务进行AJAX调用并在流程运行时检索url统计信息,以显示迄今为止收集的用户url统计信息,因为扫描大型网站需要相当长的时间.所以在每5秒后我从服务器检索统计数据.现在问题是我需要在扫描处理完成时发送的所有List变量数据,而不是在更新期间.现在正在发生的List<Stats>变化数据也是在更新期间发送的,这是大块数据,我想只发送int显示进程更新所需的类型变量.

从在互联网上搜索我找不到任何有用的解决我的问题,我发现Json.NET是非常好的库,但我真的不知道如何正确使用它来得到我想要的.

基本上我正在寻找在运行时根据其数据类型序列化属性,如果可能的话.

fer*_*ero 30

您的问题有两种不同的方法.

如果要更频繁地更改类,则应该选择第一个,因为第一种方法可以防止您忘记序列化新添加的属性.此外,如果您想以相同的方式添加要序列化的另一个类,则可以重复使用它.

如果您只有这两个类,而且最有可能的是它们不会改变,您可以选择第二种方法来保持解决方案的简单性.

1.使用自定义转换器选择所有int属性

第一种方法是使用一个自定义JsonConverter,它通过仅包含具有类型的属性来序列化类或结构int.代码可能如下所示:

class IntPropertyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // this converter can be applied to any type
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // we currently support only writing of JSON
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            serializer.Serialize(writer, null);
            return;
        }

        // find all properties with type 'int'
        var properties = value.GetType().GetProperties().Where(p => p.PropertyType == typeof(int));

        writer.WriteStartObject();

        foreach (var property in properties)
        {
            // write property name
            writer.WritePropertyName(property.Name);
            // let the serializer serialize the value itself
            // (so this converter will work with any other type, not just int)
            serializer.Serialize(writer, property.GetValue(value, null));
        }

        writer.WriteEndObject();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你必须用以下内容装饰你的课程JsonConverterAttribute:

[JsonConverter(typeof(IntPropertyConverter))]
public class UrlStats
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

免责声明:此代码仅经过非常粗略的测试.


2.单独选择属性

第二个解决方案看起来更简单:您可以使用它JsonIgnoreAttribute来装饰要排除的属性以进行序列化.或者,您可以通过明确包含要序列化的属性从"黑名单"切换到"白名单".这是一些示例代码:

黑名单:(我已重新排序属性以获得更好的概述)

[JsonObject(MemberSerialization.OptOut)] // this is default and can be omitted
public class UrlStats
{
    [JsonIgnore] public string URL { get; set; }
    [JsonIgnore] public List<Stats> TotalPages { get; set; }
    [JsonIgnore] public List<Stats> TotalTitles { get; set; }
    [JsonIgnore] public List<Stats> DuplicateTitles { get; set; }
    [JsonIgnore] public List<Stats> OverlengthTitles { get; set; }

    public int TotalPagesFound { get; set; }
    public int TotalTitleTags { get; set; }
    public int NoDuplicateTitleTags { get; set; }
    public int NoOverlengthTitleTags { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

白名单:(也重新订购)

[JsonObject(MemberSerialization.OptIn)] // this is important!
public class UrlStats
{
    public string URL { get; set; }
    public List<Stats> TotalPages { get; set; }
    public List<Stats> TotalTitles { get; set; }
    public List<Stats> DuplicateTitles { get; set; }
    public List<Stats> OverlengthTitles { get; set; }

    [JsonProperty] public int TotalPagesFound { get; set; }
    [JsonProperty] public int TotalTitleTags { get; set; }
    [JsonProperty] public int NoDuplicateTitleTags { get; set; }
    [JsonProperty] public int NoOverlengthTitleTags { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为有两个 JSONConverter。我认为 @fero 显示了 Newtonsoft.Json 中的一个,但我认为 System.Text.Json.Serialization 中也有一个。我的 .NET Core 3.1 项目不会自动从我的控制器/操作对语句“return Json(myNET_ObjectToReturn)”执行序列化,除非我使用了稍后描述的转换器:https://learn.microsoft.com/en- us/dotnet/standard/serialization/system-text-json-converters-how-to (2认同)

cor*_*ego 5

哦明白了,重新阅读你的问题我认为你可以序列化你的数据的投影。

您可以尝试以下操作:

var json = JsonConvert.SerializeObject(new { u.TotalPagesFound, u.TotalTitleTags, u.NoDuplicateTitleTags, u.NoOverlengthTitleTags } );
Run Code Online (Sandbox Code Playgroud)

这只会将类的 int 属性转换为 JSON。这是最简单的方法,并且它与类的结构相关。如果您想要更通用的东西,您将需要实现一个自定义转换器。

原答案:

我认为你的类没有问题,你没有任何奇怪的东西,比如循环引用,所以 Json.NET 序列化你的类应该没有问题。所以去获取 Json.NET 然后你可以尝试以下操作

// create new instance of your url stat class
var u = new UrlStats() { URL = "a.com", TotalPages = new List<Stats>() { new Stats() { URL = "b.com", Status = "xxxx" } } };
// seralize!
var json = JsonConvert.SerializeObject(u);
Console.Write(json);
Run Code Online (Sandbox Code Playgroud)

我用这个方法得到的是这样的:

{"URL":"a.com","TotalPagesFound":0,"TotalPages":[{"URL":"b.com","Status":"xxxx","Title":null,"Description":null,"Length":0}],"TotalTitleTags":0,"TotalTitles":null,"NoDuplicateTitleTags":0,"DuplicateTitles":null,"NoOverlengthTitleTags":0,"OverlengthTitles":null}
Run Code Online (Sandbox Code Playgroud)

对我来说这看起来是不错的 json 。