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

怎甘沉沦 提交于 2021-01-28 08:26:57

问题


My project is Application with Recipes (cooking) .NET Core 5.0

And i have problem with adding a new recipe (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."

When i'm creating a new recipe it should use recipeToCreateDto instead of Recipe - which contains all properties (circular referencing)

Could you help me how to make it working properly. How to map etc.

https://i.postimg.cc/Mphv7zRH/screen.png <- screen here

I'm using AutoMapper for mapping classes and Repository Pattern.

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

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.

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

回答1:


"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."

For this issue , you can add the following code in startup.cs ConfigureServices method:

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



回答2:


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


来源:https://stackoverflow.com/questions/64341036/how-to-avoid-the-circular-referencing-asp-net-core-mvc-httppostadd-recipe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!