【问题标题】:How to avoid the circular referencing asp.net core mvc [HttpPost("add-recipe")] web api如何避免循环引用 asp.net core mvc [HttpPost("add-recipe")] web api
【发布时间】:2021-05-24 09:05:40
【问题描述】:

我的项目是 Application with Recipes (cooking) .NET Core 5.0

我在添加新配方 (HttpPost) web api 时遇到问题

关于邮递员,我的回答是:

“检测到可能的对象循环。这可能是由于循环或对象深度大于最大允许深度 32。考虑在 JsonSerializerOptions 上使用 ReferenceHandler.Preserve 以支持循环。”

当我创建一个新配方时,它应该使用 recipeToCreateDto 而不是 Recipe - 它包含所有属性(循环引用)

您能帮我如何使它正常工作吗?如何映射等。

https://i.postimg.cc/Mphv7zRH/screen.png

我正在使用 AutoMapper 来映射类和存储库模式。

public class AppUser
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public ICollection<Recipe> Recipes {get; set;} 
    }
}

用户有很多食谱。

 public class Recipe
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public AppUser AppUser { get; set; }
        public int AppUserId { get; set; }
    }

数据传输对象

public class RecipeForCreateDto
    {
        [Required]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "You must specify name between 3 and 50 characters")]
        public string Name { get; set; }
        public int AppUserId { get; set; }
        public int AuthorId { get; set; }
    }

在我的 AutoMapperProfiles.cs 中

public class AutoMapperProfiles : Profile
    {
        public AutoMapperProfiles()
        {
        CreateMap<RecipeForCreateDto, Recipe>();
        }

配方界面

  public interface IRecipeRepository
    {
      Task<Recipe> AddNewRecipe(Recipe recipe);
    }

    public class RecipeRepository : IRecipeRepository
    {
        private readonly DataContext _context;
        private readonly IMapper _autoMapper;
        public RecipeRepository(DataContext context, IMapper autoMapper)
        {
            _autoMapper = autoMapper;
            _context = context;
        }

 public async Task<Recipe> AddNewRecipe(Recipe recipe)
        {
            await _context.Recipes.AddAsync(recipe);
            await _context.SaveChangesAsync();

            return recipe;
        }

}

用户控制器:

User.GetUsername() 是获取用户名的静态方法。

[HttpPost("add-recipe")]
        public async Task<ActionResult> AddNewRecipe(RecipeForCreateDto recipeForCreateDto)
        {
            var userFromRepo = await _userRepository.GetUserByUsernameAsync(User.GetUsername());

            recipeForCreateDto.Name = recipeForCreateDto.Name.ToLower();

            if (await _recipeRepository.RecipeExists(recipeForCreateDto.Name))
                return BadRequest("Recipe with that name already exists!");

            var recipeToCreate = _autoMapper.Map<Recipe>(recipeForCreateDto);

            recipeToCreate.AppUserId = userFromRepo.Id;


            var createdRecipe = await _recipeRepository.AddNewRecipe(recipeToCreate); // here is problem 

            var recipeToReturn = _autoMapper.Map<RecipeForDetailDto>(createdRecipe);


            return CreatedAtRoute("GetRecipe", new { controller = "Recipes", id = createdRecipe.Id }, recipeToReturn);
        }

【问题讨论】:

    标签: c# asp.net-core-mvc asp.net-core-webapi


    【解决方案1】:
    [HttpPost("{recipeForCreateDto}")]
    public async Task < ActionResult > AddNewRecipe([FromBody] RecipeForCreateDto recipeForCreateDto) {
        var userFromRepo = await _userRepository.GetUserByUsernameAsync(User.GetUsername());
    
        recipeForCreateDto.Name = recipeForCreateDto.Name.ToLower();
    
        if (await _recipeRepository.RecipeExists(recipeForCreateDto.Name)) return BadRequest("Recipe with that name already exists!");
    
        var recipeToCreate = _autoMapper.Map < Recipe > (recipeForCreateDto);
    
        recipeToCreate.AppUserId = userFromRepo.Id;
    
        var createdRecipe = await _recipeRepository.AddNewRecipe(recipeToCreate); // here is problem 
        var recipeToReturn = _autoMapper.Map < RecipeForDetailDto > (createdRecipe);
    
        return CreatedAtRoute("GetRecipe", new {
                controller = "Recipes",
                id = createdRecipe.Id
            },
            recipeToReturn);
    }
    

    【讨论】:

    • [HttpPost("{recipeForCreateDto} ")] ?我不明白你想做什么
    【解决方案2】:

    请务必注意,.Net 中的 默认序列化程序 现在来自 System.Text.Json.Serialization 命名空间。这个序列化程序实际上在序列化和反序列化循环引用方面做得很好。

    要启用此功能,请将以下代码放入您的 Startup.cs

    services
       .AddControllers()
       .AddJsonOptions(c => c.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve);
    

    在此处记录:https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-preserve-references

    【讨论】:

    • 但这与 'Newtonsoft.Json.ReferenceLoopHandling.Ignore' 的工作方式不同,因为它添加了这些 '$id' 或 '$ref' 属性。有没有办法获得与 Newtonsoft 提供的结果相同的结果?
    • 我不熟悉 Newtonsoft 使用什么作为参考。需要这些引用来重建 js 或 .net 中的反序列化关系。
    【解决方案3】:

    “检测到可能的对象循环。这可能是由于 循环或如果对象深度大于最大允许深度 32. 考虑使用 ReferenceHandler.Preserve 支持循环的 JsonSerializerOptions。"

    对于这个问题,可以在startup.csConfigureServices方法中添加如下代码:

    services.AddControllersWithViews()
        .AddNewtonsoftJson(options =>
        options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    );
    

    【讨论】:

    • 感谢您的回答,但我在通过自动映射器进行映射时遇到问题..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 2015-09-05
    • 2019-05-15
    • 1970-01-01
    • 2010-11-20
    • 2017-11-01
    相关资源
    最近更新 更多