HashSet not works in HttpPost

76 Views Asked by At

I have a insert dto

public class InsertCircularStepDto
{
    public Guid CircularId { get; set; }

    public HashSet<CircularStepPrizeDto> Prizes { get; set; }
        = new(new CircularStepPrizeDtoComparer());
}

public class CircularStepPrizeDto
{
    public Guid ProductModelId { get; set; }

    public Guid ProductModelUnitId { get; set; }

    public int Count { get; set; }
}

With this comparer

public class CircularStepPrizeDtoComparer : IEqualityComparer<CircularStepPrizeDto>
{
    public bool Equals(CircularStepPrizeDto? x, CircularStepPrizeDto? y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(x, null)) return false;
        if (ReferenceEquals(y, null)) return false;
        if (x.GetType() != y.GetType()) return false;
        return x.ProductModelId.Equals(y.ProductModelId) && x.ProductModelUnitId.Equals(y.ProductModelUnitId);
    }

    public int GetHashCode(CircularStepPrizeDto obj)
    {
        return HashCode.Combine(obj.ProductModelId, obj.ProductModelUnitId);
    }
}

I want to prevent duplicate records for prizes with same ProductModelId and ProductModelUnitId, when I use [HttpGet] it works correctly and if I send duplicate records for prize it gives me model state error:

[HttpGet]
public async Task<IActionResult> Create([FromQuery] InsertCircularStepDto request)
{
    var result = await _circularStepFacade.InsertCircularStepService.ExecuteAsync(request);
    return Ok(result);
}

But when I use [HttpPost] it doesn't works and it not prevent duplicate records of prizes with same ProductModelId and ProductModelUnitId:

// Not works
[HttpPost]
public async Task<IActionResult> Create([FromBody] InsertCircularStepDto request)
{
    var result = await _circularStepFacade.InsertCircularStepService.ExecuteAsync(request);
    return Ok(result);
}

Why my comparer works in [HttpGet] and it doesn't work in [HttpPost], I asked chat GPT And gives me this code and it's works in [HttpPost] but it doesn't return model state error, if I send duplicate records for prizes, it just remove duplicate records not return model state error:

public class InsertCircularStepDto
{
    public Guid CircularId { get; set; }

    private HashSet<CircularStepPrizeDto> _prizes = new(new CircularStepPrizeDtoComparer());

    public List<CircularStepPrizeDto> Prizes
    {
        get => _prizes.ToList();
        set => _prizes = new HashSet<CircularStepPrizeDto>(value, new CircularStepPrizeDtoComparer());
    }
}

but I want to know why HashSet<CircularStepPrizeDto> not works for me in [HttpPost] ?

1

There are 1 best solutions below

2
Shahar Shokrani On

Looks like a code smell, the real solution is to decouple the class that implements IEqualityComparer out of the DTO.

[HttpPost]
public async Task<IActionResult> Create([FromBody] InsertCircularStepDto request)
{
    var seen = new HashSet<CircularStepPrizeDto>(new CircularStepPrizeDtoComparer());

    foreach (var prize in request.Prizes)
    {
        if (!seen.Add(prize))
        {
        }
    }    
}

why it's works in [HttpGet] and only not works in [HttpPost]

This is how the model binding works the GET the model binding occurs through the query string, and POST is via the the body - so it deserilized as JSON data, it relates to the fact that its creates the collection first without considering the comparer.

If you still want to keep your solution without de-coupling the comperare from the DTO you can modify the model binding de-serilization or use a custom comparer logic