Moje preferencje to zrobić walidacji wejścia na widoku modeli i walidacji biznesu na model domeny.
Innymi słowy, wszelkie adnotacje danych, takie jak wymagane pola, sprawdzanie długości, wyrażenie regularne itp., Powinny być wykonywane w modelach widoku i dodawane do stanu modelu po wystąpieniu błędu.
Prawdopodobnie będziesz mieć reguły biznesowe/domeny, które polegają na czymś więcej niż tylko "formularzu", więc powinieneś to zrobić w modelach domenowych (wykonaj walidację po ich odwzorowaniu) lub warstwa usługowa.
Wszystkie nasze modele mają metodę zwaną "Validate", którą nazywamy usługami przed utrwaleniem. Wyrzucają niestandardowe wyjątki, jeśli nie sprawdzą poprawności biznesowej, która zostanie przechwycona przez kontroler i dodana do stanu modelu.
Może nie być filiżanką herbaty dla wszystkich, ale jest spójna.
Przykład walidacji gospodarczej, zgodnie z wnioskiem:
Oto przykład z modelu domeny mamy, która reprezentuje ogólny "post" (pytanie, zdjęć, wideo, itp):
public abstract class Post
{
// .. fields, properties, domain logic, etc
public void Validate()
{
if (!this.GeospatialIdentity.IsValidForThisTypeOfPost())
throw new DomainException(this, BusinessException.PostNotValidForThisSpatial.);
}
}
Widzisz tam, sprawdzam reguły biznesowe i rzucam niestandardowe wyjątki. DomainException
to nasza baza i mamy wiele pochodnych implementacji. Mamy wyliczenie o nazwie BusinessException
, które zawiera wartości wszystkich naszych wyjątków. W wyliczeniach używamy metod rozszerzeń, aby zapewnić komunikat o błędzie oparty na zasobach.
To nie jest po prostu pole na sprawdzanie modelu, np. "Wszystkie posty muszą mieć temat", ponieważ chociaż jest to część domeny, to przede wszystkim walidacja danych wejściowych i tym samym jest obsługiwana za pomocą adnotacji danych w modelu widoku.
Teraz kontroler:
[HttpPost]
public ActionResult Create(QuestionViewModel viewModel)
{
if (!ModelState.IsValid)
return View(viewModel);
try
{
// Map to ViewModel
var model = Mapper.Map<QuestionViewModel,Question>(viewModel);
// Save.
postService.Save(model); // generic Save method, constraint: "where TPost: Post, new()".
// Commit.
unitOfWork.Commit();
// P-R-G
return RedirectToAction("Index", new { id = model.PostId });
}
catch (Exception exc)
{
var typedExc = exc as DomainException;
if (typedExc != null)
{
// Internationalised, user-friendly domain exception, so we can show
ModelState.AddModelError("Error", typedExc.BusinessError.ToDescription());
}
else
{
// Could be anything, e.g database exception - so show generic msg.
ModelState.AddModelError("Error", "Sorry, an error occured saving the Post. Support has been notified. Please try again later.");
}
}
return View(viewModel);
}
Tak, przez czas my trafiamy do „Zapisz” metody na służbie, model przeszedł sprawdzania poprawności danych wejściowych. Następnie metoda Save wywołuje post.Validate()
, wywołując reguły biznesowe.
Jeśli zostanie zgłoszony wyjątek, kontroler go złapie i wyświetli komunikat. Jeśli przejdzie, zostanie użyta metoda Save i wystąpi kolejny błąd (na przykład 90% czasu, to Entity Framework), pokazujemy ogólny komunikat o błędzie.
Tak jak powiedziałem, nie dla wszystkich, ale to działa dobrze dla naszego zespołu. Mamy wyraźne oddzielenie prezentacji i walidacji domen oraz spójny przepływ kontroli od surowego HTTP POST do przekierowania po pomyślnym zakończeniu.
HTH
Jaki jest dokładnie twój "model biznesowy"? –
Osoba to klasa śledzona przez EntityFramework. PersonViewModel oczywiście nie jest .. przeczytaj wpis na blogu, z którym się łączyłem i zrozumiesz, jakie praktyki próbuję podążać ... stąd pytanie, gdzie powinna iść logika walidacji. – ignaciofuentes
Dzięki - przepraszam, zeskanowałem artykuł i szukałem w nim "modelu biznesowego", ale bez trafień. –