IValidatableObject vs responsabilidade única

12

Gosto do ponto de extensibilidade do MVC, permitindo que os modelos de visualização implementem IValidatableObject e adicione validação personalizada.

Eu tento manter meus controladores magros, tendo esse código como a única lógica de validação:

if (!ModelState.IsValid)
    return View(loginViewModel);

Por exemplo, um modelo de visualização de logon implementa IValidatableObject, obtém o objeto ILoginValidator via injeção do construtor:

public interface ILoginValidator
{
    bool UserExists(string email);
    bool IsLoginValid(string userName, string password);
}

Parece que o Ninject, injetar instâncias nos modelos de exibição não é realmente uma prática comum, pode até ser um anti-padrão?

Será esta uma boa abordagem? Existe um melhor?

Boris Yankov
fonte
Se você deseja a validação em um objeto separado, tente FluentValidation. Consulte fluentvalidation.codeplex.com/wikipage?title=mvc .
RMAC
+1 Ótima idéia para injetar uma classe Validator separada, que resolva meu problema onde eu tenho que acessar as informações do banco de dados para validação!
magnattic

Respostas:

7

Pessoalmente, para mim, seu design parece limpo.

IValidatableObject significa que o modelo de exibição fornecerá alguma validação que não pode ser fornecida por atributos simples - injetando o validador real que chamará serviços / bancos de dados / o que mantém seu design limpo e garante que você não viola o princípio da responsabilidade única - os modelos de exibição são responsável, essencialmente, pela transferência e validação dos dados transferidos (seja por meio de atributos ou IValidatableObject ou ambos).

David_001
fonte
4

Ter um objeto dedicado para validação garante que você realmente respeite o SRP - o que já era o caso, pois é uma responsabilidade típica de um modelo de exibição validar seus dados.

Quanto à injeção de instâncias nos modelos de exibição, não vejo nada de errado nisso. Praticamente não há limite para o que pode ser injetado no quê.

guillaume31
fonte
3

Em vez de injetar o ILoginValidator no construtor da VM, você pode usar o ValidationContext (que é o argumento para IValidatableObject.Validate ()) para obter seu validador.

public IEnumerable<ValidationResult> Validate(ValidationContext vc)
{

var loginValidator = (ILoginValidator)vc.GetService(typeof(ILoginValidator));
return loginValidator.Validate();

}
Kelly
fonte