You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core中HttpGet方法自定义对象序列化失败问题

问题:ASP.NET Core MVC + MongoDB API返回JSON时Schedule字段为空

我正在开发基于ASP.NET Core MVC和MongoDB的小型API,参考微软官方文档实现,但遇到HttpGet请求返回时对象序列化异常的问题:从MongoDB读取的Group对象数据正常,但返回的JSON中schedule字段为空(实际应包含Weekday列表)。


模型代码

[Serializable]
public class Group
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string? Id { get; set; }
    public string groupName { get; set; }
    public Schedule schedule { get; set; }
    public Group()
    {
        groupName = "UNKNOWN";
        schedule = new Schedule();
    }
    public Group(string groupName)
    {
        this.groupName = groupName;
        schedule = new Schedule();
    }
    
}

[Serializable]
public class Schedule
{
    
    public List<Weekday> week = new List<Weekday>();
}
[Serializable]
public class Weekday
{
    public List<DaysSchedule> daysSchedules { get; set; } = new List<DaysSchedule>();
    public int dayNumber { get; set; } = 0;
}

public class DaysSchedule
{
    public List<string> dates = new List<string>();
    public List<Classes> classes = new List<Classes>();
}
public class Classes
{
    [BsonElement("ordinal")]
    public int ordinal { get; set; }
    [BsonElement("name")]
    public string name { get; set; }
    [BsonElement("teacher")]
    public string? teacher { get; set; }
    [BsonElement("type")]
    public string type { get; set; }
    [BsonElement("location")]
    public string location { get; set; }
    public Classes()
    {
        ordinal = 0;
        name = "UNKNOWN";
        type = "UNDEFINED";
        location = "UNDEFINED";
    }
    public Classes(int ordinal, string name, string teacher, string type, string location)
    {
        this.ordinal = ordinal;
        this.name = name;
        this.teacher = teacher;
        this.type = type;
        this.location = location;
    }
}

期望返回的JSON

{
"Id": "63ea85829903ec2ab03720d3",
"groupName": "М3О-225Бк-21",
"schedule": {
  "week": [
    {
      "daysSchedules": [
        {
          "dates": [
            "13.02.2023",
            "13.02.2023"
          ],
          "classes": [
            {
              "ordinal": 0,
              "name": "Math",
              "teacher": "Lyahner",
              "type": "PZ",
              "location": "64"
            }
          ]
        }
      ],
      "dayNumber": 0
    }
  ]
}
}

实际返回的JSON

{
  "id": "63ea85829903ec2ab03720d3",
  "groupName": "М3О-225Бк-21",
  "schedule": {}
}

控制器代码

using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
using ThreeplyWebApi.Services;
using ThreeplyWebApi.Models;
using System.Text.Json;

namespace ThreeplyWebApi.Controllers
{
    [ApiController]
    [Route("controller")]
    public class GroupsController : ControllerBase
    {
        readonly private GroupsService _groupsService;

        public GroupsController(GroupsService schedulesService)
        {
            _groupsService = schedulesService;
        }
        [HttpGet]
        public async Task<List<Group>> Get() => await _groupsService.GetAsync();

        [HttpGet("{groupName}")]
        public async Task<ActionResult<Group>> Get(string groupName)
        {
            var group = await _groupsService.GetAsync(groupName);
            if (group == null)
            {
                return NotFound();
            }
            return Ok(group);
        }
        [HttpPost]
        public async Task<IActionResult> Post([FromBody]Group newGroup) 
        {
            await _groupsService.CreateAsync(newGroup);
            return CreatedAtAction(nameof(Get), new { groupName = newGroup.groupName }, newGroup);

        }
    }
}

数据库服务代码

namespace ThreeplyWebApi.Services
{

    public class GroupsService
    {
        private readonly IMongoCollection<Group> _groupsCollection;
        public GroupsService(IOptions<GroupsDatabaseSettings> groupDatabaseSettings)
        {
            var MongoClient = new MongoClient(groupDatabaseSettings.Value.ConnectionString);
            var MongoDatabase = MongoClient.GetDatabase(groupDatabaseSettings.Value.DatabaseName);
            _groupsCollection = MongoDatabase.GetCollection<Group>(groupDatabaseSettings.Value.GroupsCollectionName);
        }
        public async Task<List<Group>> GetAsync()
        {
          return await _groupsCollection.Find<Group>(_ => true).ToListAsync();
        }
        public async Task<Group> GetAsync(string groupName)
        {
           return  await _groupsCollection.Find(x => x.groupName == groupName).FirstOrDefaultAsync();   
        }
        
        public async Task CreateAsync(Group group) {
            await _groupsCollection.InsertOneAsync(group);
        }
        
        public async Task UpdateAsync(string groupName, Group updatedGroup) =>
            await _groupsCollection.ReplaceOneAsync(x => x.groupName == groupName, updatedGroup);
        public async Task RemoveAsync(string groupName) =>
            await _groupsCollection.DeleteOneAsync(x => x.groupName == groupName);
    }
    
}

疑问

不清楚HttpGet/HttpPost属性的序列化时机,尝试用Newtonsoft.Json显式序列化可行,但希望找到规范的解决方案,同时想了解如何为Group对象配置自定义序列化,以便在带路由属性的方法中直接返回。


解决方案

核心问题:字段未被序列化

ASP.NET Core默认使用System.Text.Json进行序列化,而System.Text.Json只会序列化公共属性(Property),不会序列化公共字段(Field)。你的Schedule类中的week、DaysSchedule中的dates和classes都是字段,不是属性,所以序列化时被忽略了。

步骤1:将字段改为属性

把模型中的字段替换为带getter/setter的属性:

[Serializable]
public class Schedule
{
    // 改为属性
    public List<Weekday> week { get; set; } = new List<Weekday>();
}

public class DaysSchedule
{
    // 改为属性
    public List<string> dates { get; set; } = new List<string>();
    public List<Classes> classes { get; set; } = new List<Classes>();
}

步骤2:(可选)统一使用Newtonsoft.Json

如果你习惯使用Newtonsoft.Json(Json.NET)而非默认的System.Text.Json,可以全局替换序列化器:

  1. 安装NuGet包:Microsoft.AspNetCore.Mvc.NewtonsoftJson
  2. 在Program.cs中配置:
builder.Services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        // 可添加自定义配置,比如保留原字段名、忽略空值等
        options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
    });

步骤3:自定义序列化规则(按需)

针对System.Text.Json:

用JsonPropertyName指定JSON字段名,或实现自定义转换器:

// 指定字段名示例
public class Group
{
    [JsonPropertyName("group_id")]
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string? Id { get; set; }
}

// 自定义转换器示例
public class GroupConverter : JsonConverter<Group>
{
    public override Group Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 自定义反序列化逻辑
        using var doc = JsonDocument.ParseValue(ref reader);
        var root = doc.RootElement;
        return new Group
        {
            Id = root.GetProperty("group_id").GetString(),
            groupName = root.GetProperty("groupName").GetString() ?? "UNKNOWN"
        };
    }

    public override void Write(Utf8JsonWriter writer, Group value, JsonSerializerOptions options)
    {
        // 自定义序列化逻辑
        writer.WriteStartObject();
        writer.WriteString("group_id", value.Id);
        writer.WriteString("groupName", value.groupName);
        JsonSerializer.Serialize(writer, value.schedule, options);
        writer.WriteEndObject();
    }
}

// 注册转换器
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new GroupConverter());
    });

针对Newtonsoft.Json:

用JsonProperty指定字段名,或实现自定义转换器:

// 指定字段名示例
public class Group
{
    [JsonProperty("group_id")]
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string? Id { get; set; }
}

// 自定义转换器示例
public class GroupConverter : Newtonsoft.Json.JsonConverter<Group>
{
    public override void WriteJson(JsonWriter writer, Group value, Newtonsoft.Json.JsonSerializer serializer)
    {
        writer.WriteStartObject();
        writer.WritePropertyName("group_id");
        serializer.Serialize(writer, value.Id);
        writer.WritePropertyName("groupName");
        serializer.Serialize(writer, value.groupName);
        writer.WritePropertyName("schedule");
        serializer.Serialize(writer, value.schedule);
        writer.WriteEndObject();
    }

    public override Group ReadJson(JsonReader reader, Type objectType, Group existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
    {
        var obj = JObject.Load(reader);
        return new Group
        {
            Id = obj["group_id"]?.ToString(),
            groupName = obj["groupName"]?.ToString() ?? "UNKNOWN",
            schedule = obj["schedule"]?.ToObject<Schedule>(serializer) ?? new Schedule()
        };
    }
}

// 全局注册或在类上标记[JsonConverter(typeof(GroupConverter))]

序列化时机说明

  • 控制器返回Ok(object)或直接返回对象时,响应准备阶段会自动序列化对象为JSON响应体;
  • HttpPost的[FromBody]会在请求接收阶段自动反序列化请求体为对象。

内容的提问来源于stack exchange,提问作者Wayne301

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 02:39:25