A validação do modelo ASP.NET MVC quebra a regra MVC?
-
15-11-2019 - |
Pergunta
usando ASP.NET MVC, tenho um modelo ao qual estou anexando atributos para poder usar a validação vinculada ao modelo MVC, mas para isso não quebra a regra do MVC, onde você está colocando itens que pertencem à View, no Model?Espero não tentar ser inteligente, mas estou curioso para saber a opinião dos outros.
public class Payments
{
[DataType(DataType.Text)]
[DisplayFormat(NullDisplayText="")]
[Display(Name="Payment Id")]
[Required(ErrorMessage="Required")]
public int PaymentId { get; set; } //todo: make this into a dropdown
[DataType(DataType.Text)]
[Display(Name="Bill Name")]
[Required(ErrorMessage = "Required")]
public string PaymentName { get; set; }
[DataType(DataType.Date)]
[Display(Name="Date to Post Payment")]
[Required(ErrorMessage = "Required")]
public DateTime PaymentDate { get; set; }
[DataType(DataType.Currency)]
[Range(0, 922337203685477.5807)]
[Required(ErrorMessage = "Required")]
public double PaymentAmount { get; set; }
}
Solução
Sim.É por isso que você deve usar ViewModels.
Outras dicas
Você pode, mas não é obrigatório, colocar esses atributos de validação em seu modelo.
Mas é melhor usar um ViewModel:
public class PaymentsViewModel
{
[DataType(DataType.Text)]
[DisplayFormat(NullDisplayText="")]
[Display(Name="Payment Id")]
[Required(ErrorMessage="Required")]
public int PaymentId { get; set; } //todo: make this into a dropdown
[DataType(DataType.Text)]
[Display(Name="Bill Name")]
[Required(ErrorMessage = "Required")]
public string PaymentName { get; set; }
[DataType(DataType.Date)]
[Display(Name="Date to Post Payment")]
[Required(ErrorMessage = "Required")]
public DateTime PaymentDate { get; set; }
[DataType(DataType.Currency)]
[Range(0, 922337203685477.5807)]
[Required(ErrorMessage = "Required")]
public double PaymentAmount { get; set; }
}
E na sua visão, em vez de:
@model YourProject.Models.Payments
você usa:
@model YourProject.Models.PaymentsViewModel
para validação.
Isso viola o MVC no sentido estrito, sim, provavelmente.Há momentos em que não há mal nenhum em violar isso?Claro.No entanto, existem mecanismos para ajudá-lo e manter as preocupações separadas.
Você pode usar seus objetos de domínio persistentes nas visualizações e validá-los, mas quando sua visualização começa a ficar complicada, os ViewModels se tornam uma necessidade.Para modelos de domínio simples ou visualizações somente visualização (não edições/criações), às vezes eu falsifico um pouco e os envio para a visualização como parte de um objeto composto:
class MyViewModel
{
public MyDomainModel DomainObj;
public int OtherViewInfo;
}
No entanto, para criar e editar cenários, os ViewModels são muito melhores.Eles permitem controle total sobre os dados que estão sendo enviados para a visualização e de a vista.
Se você estiver usando EF 4.1 e CodeFirst, sim, você acabará com alguma duplicação de atributos e propriedades entre o domínio e o ViewModel.Isso é inevitável, mas oferece a flexibilidade de fazer diferentes validações específicas para a visualização.
Achei útil ter uma camada extra de proteção no controlador ao salvar o objeto de domínio, caso eu tenha perdido alguma validação na visualização:
public class MyController : Controller
{
[HttpPost]
public ActionResult Edit(int id, MyViewModel model)
{
try
{
...Do stuff, check ModelState.IsValid...
_context.SaveChanges()
}
catch (DbEntityValidationException dbEx)
{
// Catch any validation errors on the domain that weren't duplicated
// in the viewmodel
ModelState.AddModelError("Form", dbEx);
}
return View(model);
}
}
A próxima pergunta a ser feita é como você mapeia entre o modelo de domínio e o ViewModel.Existem várias estratégias e ferramentas por aí - AutoMapper e Injetor de valor (sim, escrito errado).Pessoalmente, tenho usado o ValueInjecter, embora se você configurar uma camada de mapeamento, poderá tentar ambos.Descobri que nenhum deles funcionará em 100% dos casos, ou pelo menos consegui descobrir como fazer o que precisava, mas um serviço de mapeamento facilita a definição de mapas personalizados da esquerda para a direita.