The @utluiz response is correct within a context in 3 layers (presentation, service and data), but as we are talking about MVC, the validation should be done, essentially, in the Model
, but not just in it.
Why?
The essential function of Model
is to model how information circulates within the system, from the point of view of each entity. The essential function of the Controller
is to harmonize and coordinate information flows - coming from the presentation, the data layer or some external service.
Therefore, validation functions of any data are normally generated at the level of Model
. The Controller
only interprets this result of the validations. It is done so because the validation is an aspect at the level of the data. Elegantly, this is done in ASP.NET MVC using Attributes
.
However, relationships between entities (Models
) are resolved at the level of Controller
(comparisons, insertions, exclusions, ordering, etc.).
Examples
Consider the Model Pessoa
down below:
public class Pessoa
{
[Key]
public Guid PessoaId {get;set;}
[Display(Name = "Nome")]
[Required(ErrorMessage = "O preenchimento do nome da pessoa é obrigatório.")]
public String Nome {get;set;}
[Required(ErrorMessage = "O preenchimento do CPF da pessoa é obrigatório.")]
[CPF]
public Decimal Cpf {get;set;}
public virtual ICollection<Produto> Produtos {get;set;}
}
By saving a Pessoa
bank, I don’t need to write a single validation line in my Controller
because all aspects of data are being processed within the Model
succinctly: the CPF has an attribute that validates the CPF, the name cannot be filled out empty and the primary key needs to be unique ([Key]
).
The Controller
does nothing here but check through another class if the Model
is valid:
[HttpPost]
public ActionResult Create(Pessoa pessoa)
{
// Se o Model for válido
if (ModelState.IsValid)
{
// Gera a chave, salva e retorna
pessoa.PessoaId = Guid.NewGuid();
context.Pessoas.Add(pessoa);
context.SaveChanges();
return RedirectToAction("Index");
}
// Se não for válido, simplesmente retorna o objeto Pessoa de novo.
// O resultado das validações está dentro da classe ModelState.
return View(pessoa);
}
Suppose now I want to grant a discount on one Produto
acquired by the user. This aspect is dealt with in Controller
because we are dealing with a Pessoa
and the Produtos
acquired by her:
public class PessoasController : Controller
{
...
public ActionResult ConcederDescontoUltimoProduto(Guid? id)
{
var pessoa = context.Pessoas.Include(p => p.Produtos).SingleOrDefault(p => p.PessoaId == id);
if (pessoa.Produtos.Count > 5)
{
var produto = pessoa.Produtos.Last();
// Vou conceder 10% de desconto no valor do produto
produto.Preco -= produto.Preco * 0.1;
context.Entry(produto).State = EntityState.Modified;
context.SaveChanges();
}
return RedirectToAction("Index");
}
}
It is still possible to leave this negotiating aspect to other specific classes, but I consider it a long and unnecessary effort, in which nothing contributes to the security and responsibility of classes in the system.
Nice that Pattern, I did not know, but could give examples of code? There in the image is architecture, where in . net, would be a new class library
– Rod
@Rod I don’t know the architecture well . Net... Sorry :(
– utluiz
Search on BLL C#, is the responsible layer.
– user6026