简体   繁体   English

如何避免循环引用asp.net core mvc [HttpPost("add-recipe")] web api

[英]How to avoid the circular referencing asp.net core mvc [HttpPost("add-recipe")] web api

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

And i have problem with adding a new recipe (HttpPost) web api我在添加新配方 (HttpPost) web api 时遇到问题

On postman my response is:在邮递员我的回答是:

"A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles." “检测到可能的对象循环。这可能是由于循环或对象深度大于最大允许深度 32。考虑在 JsonSerializerOptions 上使用 ReferenceHandler.Preserve 以支持循环。”

When i'm creating a new recipe it should use recipeToCreateDto instead of Recipe - which contains all properties (circular referencing)当我创建一个新配方时,它应该使用 recipeToCreateDto 而不是 Recipe - 它包含所有属性(循环引用)

Could you help me how to make it working properly.你能帮我如何让它正常工作吗? How to map etc.如何映射等。

https://i.postimg.cc/Mphv7zRH/screen.png <- screen here https://i.postimg.cc/Mphv7zRH/screen.png <- 屏幕在这里

I'm using AutoMapper for mapping classes and Repository Pattern.我正在使用 AutoMapper 来映射类和存储库模式。

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

User has many recipes.用户有很多食谱。

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

Data Transfer Object数据传输对象

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; }
    }

In my AutoMapperProfiles.cs在我的 AutoMapperProfiles.cs

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

Recipe Interface配方界面

  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;
        }

} }

Users Controller:用户控制器:

User.GetUsername() is static method that is getting User's username. 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);
        }
[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);
}

"A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles." “检测到可能的对象循环。这可能是由于循环或对象深度大于最大允许深度 32。考虑在 JsonSerializerOptions 上使用 ReferenceHandler.Preserve 以支持循环。”

For this issue , you can add the following code in startup.cs ConfigureServices method:针对这个问题,可以在startup.cs的ConfigureServices方法中添加如下代码:

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

It is important to note that the default serializer in .Net is now from the System.Text.Json.Serialization namespace.需要注意的是,.Net 中的默认序列化器现在来自System.Text.Json.Serialization命名空间。 This serializer actually does a great job of both serializing and deserializing circular references .这个序列化器实际上在序列化和反序列化循环引用方面做得很好。

To turn this feature on place the following code in your Startup.cs :要打开此功能,请在Startup.cs 中放置以下代码:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM