ASP.NET Core Web API如何仅返回子对象ID?
使用特性实现ASP.NET Core Web API子对象仅返回Id
可以通过自定义特性结合JSON序列化扩展来实现这个需求,无需创建大量中间DTO对象。以下是具体实现步骤:
1. 定义自定义特性
创建一个标记特性,用来标识哪些导航属性只需要返回Id:
[AttributeUsage(AttributeTargets.Property)] public class OnlyReturnIdAttribute : Attribute { }
2. 标记实体类属性
在ProjectItem类中,给需要仅返回Id的导航属性添加该特性:
public class ProjectItem { [Key] public int Id { get; set; } public string Title { get; set; } = ""; public DateTime Created { get; set; } // 该属性保持完整序列化 public virtual User? CreatedByUser { get; set; } // 仅返回子项的Id [OnlyReturnId] public virtual ICollection<ProjectItem> Children { get; } = new List<ProjectItem>(); // 仅返回父项的Id [OnlyReturnId] public virtual ProjectItem? Parent { get; set; } }
3. 实现自定义JSON转换器
编写一个JSON转换器,处理带有OnlyReturnId特性的属性,序列化时仅输出Id字段:
public class OnlyReturnIdConverter : JsonConverter<object> { public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 若无需反序列化,可直接抛出异常或返回默认值 throw new NotImplementedException("反序列化功能暂未实现"); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { // 处理集合类型(如Children) if (value is IEnumerable enumerable) { writer.WriteStartArray(); foreach (var item in enumerable) { WriteSingleItem(writer, item, options); } writer.WriteEndArray(); return; } // 处理单个对象(如Parent) WriteSingleItem(writer, value, options); } private void WriteSingleItem(Utf8JsonWriter writer, object? item, JsonSerializerOptions options) { if (item == null) { writer.WriteNullValue(); return; } var idProperty = item.GetType().GetProperty("Id"); if (idProperty == null) { // 若无Id属性,按默认规则序列化 JsonSerializer.Serialize(writer, item, options); return; } var idValue = idProperty.GetValue(item); writer.WriteStartObject(); writer.WritePropertyName("id"); JsonSerializer.Serialize(writer, idValue, options); writer.WriteEndObject(); } }
4. 配置全局JSON序列化规则
在Program.cs中配置JSON选项,使用自定义契约解析器识别特性并应用转换器:
public class OnlyReturnIdContractResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { var jsonTypeInfo = base.GetTypeInfo(type, options); foreach (var property in jsonTypeInfo.Properties) { // 检查属性是否带有OnlyReturnId特性 if (property.AttributeProvider?.GetCustomAttributes(typeof(OnlyReturnIdAttribute), inherit: true).Any() == true) { property.CustomConverter = new OnlyReturnIdConverter(); } } return jsonTypeInfo; } } // 在服务配置中添加 builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.ContractResolver = new OnlyReturnIdContractResolver(); // 可选:设置驼峰命名,匹配示例响应格式 options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; });
5. 修正控制器代码(可选)
注意到你的控制器中返回的是MyItem,但实体类是ProjectItem,需要统一类型:
[HttpGet("GetById")] public async Task<ActionResult<ProjectItem>> GetById(int id) { var item = await _context.FindAsync<ProjectItem>(id); if (item == null) return NotFound(); return Ok(item); }
这样配置后,接口返回的响应会自动将带有OnlyReturnId特性的属性序列化为仅含Id的对象/数组,其他属性保持完整序列化,完全符合你的期望格式。
内容的提问来源于stack exchange,提问作者Bas Visscher
相关产品推荐
相关产品推荐

