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

.NET 5项目中如何排除导航属性指定字段 避免JSON输出敏感信息

解决方案

你当前的问题根源是ArticleListDto直接包含了数据库实体Article集合,序列化时会递归输出实体所有属性、导航属性,仅配置ReferenceLoopHandling.Ignore只能解决循环引用报错,无法过滤多余敏感字段。以下是三种实现方案,优先推荐第一种,和你熟悉的Django Rest Framework Serializer逻辑完全对齐:


方案1:自定义DTO(数据传输对象,最规范推荐)

该方案完全解耦API输出结构和数据库实体,和DRF自定义Serializer的作用一致,未在DTO中定义的字段默认不会被序列化,天然实现字段过滤。

  1. 定义各层级输出DTO,仅保留需要返回的字段:
// 用户输出DTO,排除PasswordHash、Articles等字段
namespace Blog.Entities.Dtos
{
    public class UserOutputDto
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        // 仅添加你需要对外暴露的用户字段,不要加PasswordHash、Articles等
    }
}
// 分类输出DTO,排除Articles导航属性
namespace Blog.Entities.Dtos
{
    public class CategoryOutputDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
        // 仅添加你需要对外暴露的分类字段,不要加Articles等
    }
}
// 文章输出DTO
namespace Blog.Entities.Dtos
{
    public class ArticleOutputDto
    {
        public string Title { get; set; }
        public string Content { get; set; }
        public string Thumbnail { get; set; }
        public DateTime Date { get; set; }
        public int ViewsCount { get; set; }
        public int CommentCount { get; set; }
        public string Slug { get; set; }
        public string SeoAuthor { get; set; }
        public string SeoDescription { get; set; }
        public string SeoTags { get; set; }
        // 用DTO替代原实体类的导航属性
        public CategoryOutputDto Category { get; set; }
        public UserOutputDto User { get; set; }
    }
}
  1. 修改ArticleListDto:
namespace Blog.Entities.Dtos
{
    public class ArticleListDto : DtoGetBase
    {
        public IList<ArticleOutputDto> Articles { get; set; }
    }
}
  1. 配置AutoMapper映射规则,你已经在Startup中注册了AutoMapper,新增映射配置类即可:
public class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        CreateMap<Article, ArticleOutputDto>();
        CreateMap<User, UserOutputDto>();
        CreateMap<Category, CategoryOutputDto>();
    }
}
  1. 修改业务层GetAll方法,将查询到的实体转换为DTO后返回:
public async Task<IDataResult<ArticleListDto>> GetAll()
{
    var articles = await _unitOfWork.Articles
                                    .GetAllAsync(null, a => a.User, a => a.Category);
    if (articles.Count > -1)
    {
        // 实体转DTO
        var outputArticles = _mapper.Map<List<ArticleOutputDto>>(articles);
        return new DataResult<ArticleListDto>(ResultStatus.Success, new ArticleListDto()
                {
                    Articles = outputArticles,
                    ResultStatus = ResultStatus.Success
                });
    }
    return new DataResult<ArticleListDto>(ResultStatus.Error, Messages.ArticleMessages.ArticleNotFound, null);
}

方案2:[JsonIgnore]属性(临时快速过滤)

如果不想定义太多DTO,可直接在数据库实体类的敏感字段上添加[JsonIgnore]属性,序列化时会自动跳过该字段:

public class User : EntityBase, IEntity
{
    // 其他字段...
    [JsonIgnore] // 序列化时忽略该字段
    public string PasswordHash { get; set; }
    [JsonIgnore]
    public ICollection<Article> Articles { get; set; }
}

public class Category : EntityBase, IEntity
{
    // 其他字段...
    [JsonIgnore]
    public ICollection<Article> Articles { get; set; }
}

注意:该配置全局生效,若其他接口需要返回这些字段则无法适配,灵活度低于DTO方案。


方案3:动态序列化过滤(按需自定义)

如果需要不同接口返回不同字段,可自定义Newtonsoft.Json序列化过滤器,实现类似DRFexclude参数的动态过滤效果,一般场景下前两种方案即可覆盖需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:36:00