Walidacja unikalnego loginu przy edycji użytkownika

0

Hej.,

używam FluentValidation i podczas dodawania usera waliduję go np. tak:

public RegisterUserRequestValidator(ApplicationDbContext dbContext)
{
  RuleFor(x => x.Email)
      .NotEmpty()
      .EmailAddress();

  RuleFor(x => x.Email)
      .Custom((value, context) =>
      {
        var emailInUse = dbContext.Users.Any(u => u.Email == value);
        if (emailInUse)
        {
          context.AddFailure("Email", "That email is taken");
        }
      });

  RuleFor(x => x.Password).MinimumLength(8);

  RuleFor(x => x.ConfirmPassword).Equal(e => e.Password);
}

teraz gdy usera już mam i chce go edytować - no właśnie jak to tego podchodzicie - czy pozwalać na edycję loginu?

Jeśli tak to zastosowanie powyższej reguły podczas edycji i braku zmiany loginu zaskutkuje błędem walidacji. Jak to robicie? Jak odpuścić walidację gdy login nie został zmieniony?

0

Sprawdzasz czy login istnieje ale dla innego IDka. Czyli inny user ma ten login. Wtedy leci error. Bo zakładam, że przy edycji podajesz jakieś Id. Czy to int czy Guid

0

to fakt, mam ID w request
zastanawiam się teraz jak do

RuleFor(x => x.Email)
      .Custom((value, context) =>
      {
        var emailInUse = dbContext.Users.Any(u => u.Email == value);
        if (emailInUse)
        {
          context.AddFailure("Email", "That email is taken");
        }
      });

dodać to co podpowiedziałeś

0
var emailInUse = dbContext.Users.Any(u => u.Email == value && u.Id!=TuTwojeId);
1
szydlak napisał(a):
var emailInUse = dbContext.Users.Any(u => u.Email == value && u.Id!=TuTwojeId);

Zrób tak aby do Custom przekazywać nie tylko email ale cały request/command.

Btw: Jak tworzysz customową funkcję to lepiej w tym przypadku async użyć

 RuleFor(x=>x)
                .CustomAsync()
0

przy tym dostaję i dla Id podobnie
Error CS1061: 'string' does not contain a definition for 'Email' and no accessible extension method 'Email' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

RuleFor(x => x.Email)
                .Custom((EditAccountRequest req, context) =>
                {
                    var emailInUse = dbContext.Users.Any(u => u.Email == req.Email && u.Id != req.Id);
                    if (emailInUse)
                    {
                        context.AddFailure("Email", "That email is taken");
                    }
                });
1
john_doe napisał(a):

przy tym dostaję i dla Id podobnie
Error CS1061: 'string' does not contain a definition for 'Email' and no accessible extension method 'Email' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

bardziej tak powinno być

RuleFor(x => x)
                .Custom((EditAccountRequest req, context) =>
                {
                    var emailInUse = dbContext.Users.Any(u => u.Email == req.Email && u.Id != req.Id);
                    if (emailInUse)
                    {
                        context.AddFailure("Email", "That email is taken");
                    }
                });

A najlepiej to chyba tak:

RuleFor(x => x)
                .CustomAsync(async (EditAccountRequest req, context, ct) =>
                {
                    var emailInUse = await dbContext.Users.AnyAsync(u => u.Email == req.Email && u.Id != req.Id, ct);
                    if (emailInUse)
                    {
                        context.AddFailure("Email", "That email is taken");
                    }
                });
4
john_doe napisał(a):

teraz gdy usera już mam i chce go edytować - no właśnie jak to tego podchodzicie - czy pozwalać na edycję loginu?

Robię tak, jak biznes chce. Bo to nie jest problem techniczny tylko biznesowy właśnie.

Jeśli tak to zastosowanie powyższej reguły podczas edycji i braku zmiany loginu zaskutkuje błędem walidacji. Jak to robicie? Jak odpuścić walidację gdy login nie został zmieniony?

Inny walidator dla akcji tworzenia użytkownika, inny dla akcji edycji użytkownika.

Ale ja bym się najpierw zastanowił nad dwiema rzeczami:

  1. czy to dobry pomysł, aby walidator używał dbContextu?
  2. czy w ogóle walidacja unikalności loginu ma sens w walidatorze?
0

@somekind:

czy to dobry pomysł, aby walidator używał dbContextu?

tak co do zasady?

no to jeżeli już decydujesz się oprzeć swoją walidacje o jakiś "framework", to czemu by go w pełni nie wykorzystać aniżeli tylko do walidacji literek?

1

czy w ogóle walidacja unikalności loginu ma sens w walidatorze?

Moim zdaniem nie ma. Jest to część procesu biznesowego, a więc powinna znaleźć się w odpowiednim handlerze/serwisie aplikacyjnym.

Fluentvalidations są fajne do wstępnej walidacji pól dto/view modelu w warstwie api/prezentacji, ale to nie jest miejsce na jakąkolwiek logikę bo potem konczymy z rozmyciem logiki po n warstwach.

0
WeiXiao napisał(a):

tak co do zasady?

no to jeżeli już decydujesz się oprzeć swoją walidacje o jakiś "framework", to czemu by go w pełni nie wykorzystać aniżeli tylko do walidacji literek?

To biblioteka akurat, ale mniejsza z tym.

Moim argumentem przeciwko jest to, ze taka walidacja niczego nie daje i przed niczym nie zabezpiecza. Za to jest ryzyko, że ktoś uwierzy, że zabezpiecza, a potem się zdziwi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1