Umieszczamy naszą aplikację i logikę biznesową na oddzielnych warstwach (plik csproj), warstwę domeny dla logiki biznesowej i warstwę usług dla logiki aplikacji. To całkowicie usuwa je z projektu MVC. Ma to dla nas dwie duże korzyści. Po pierwsze, logika biznesowa nie jest powiązana z wzorcem, który mógłby się zmienić. Kilka lat temu nikt z nas nie wyobrażał sobie dziś popularności MVC, a za kilka lat nie wiemy, czy pojawią się nowe rzeczy, które pojawią się i zastąpią MVC, tak aby uzyskać znaczną większość kodu "niezwiązany" z MVC pomógłby, gdybyś kiedykolwiek chciał porzucić MVC na coś innego.
Drugą zaletą jest to, że bardzo różne warstwy prezentacji są łatwe do wdrożenia. Więc jeśli chcesz przedstawić swoją logikę biznesową jako usługę WCF, możesz to zrobić bardzo łatwo, tworząc nowy projekt WCF i tworząc tę fasadę dla twoich Usług i warstw domen. Ułatwia to konserwację, ponieważ zarówno projekt MVC, jak i usługa WCF będą korzystać z tych samych klas Business Logic.
Przykład Poniżej znajduje się przykładowy kod tego, co zrobiłbym. Jest to szybki i brudny i nie powinno być więcej, jak dodawanie rejestrowanie jeśli użytkownik nie zapisać z powrotem do bazy danych itp ...
public enum PayoutResult
{
UserNotFound,
Success,
FundsUnavailable,
DBError
}
public class UserProfile
{
public float Balance { get; set; }
public string Username { get; set; }
// other properties and domain logic you may have
public bool Withdraw(PayoutModel model)
{
if (this.Balance >= model.Amount)
{
this.Balance -= model.Amount;
return true;
}
return false;
}
}
public class PayoutService
{
IUserRepository userRepository;
public PayoutService()
{
this.userRepository = new UserRepository();
}
public PayoutResult Payout(string userName, PayoutModel model)
{
var user = this.userRepository.GetAll().SingleOrDefault(u => u.Username == userName);
if (user == null)
{
return PayoutResult.UserNotFound;
}
// don't set the model properties until we're ok on the db
bool hasWithdrawn = user.Withdraw(model);
if (hasWithdrawn && this.userRepository.SaveUser(user))
{
model.Balance = user.Balance;
model.Amount = 0;
return PayoutResult.Success;
}
else if (hasWithdrawn)
{
return PayoutResult.DBError;
}
return PayoutResult.FundsUnavailable;
}
}
Twój kontroler będzie teraz wyglądać tak
[HttpPost]
public ActionResult Payout(PayoutModel model)
{
if (ModelState.IsValid)
{
var result = service.Payout(User.Identity.Name, model);
// This part should only be in the MVC project since it deals with
// how things should be presented to the user
switch (result)
{
case PayoutResult.UserNotFound:
ViewBag.Message = "User not found";
break;
case PayoutResult.Success:
ViewBag.Message = string.Format("Successfully withdraw {0:c}", model.Balance);
break;
case PayoutResult.FundsUnavailable:
ViewBag.Message = "Insufficient funds";
break;
default:
break;
}
}
return View(model);
}
A gdybyś musiał ujawnić zapłatę w usłudze sieciowej (pracuję w środowisku korporacyjnym, więc to dużo dla mnie) Wykonujesz następujące czynności ...
public class MyWCFService : IMyWCFService
{
private PayoutService service = new PayoutService();
public PayoutResult Payout(string username, PayoutModel model)
{
return this.service.Payout(username, model);
}
}
Zalecam umieszczenie całego kodu w modelu domeny. To sprawia, że kontroler jest znacznie czystszy. –
@DarrenDavies Więc nawet ModelState.IsValid należy umieścić w modelu domeny? –
Nie, 'ModelState.IsValid' jest materiałem MVC, umieściłbym część warunkową' if' w domenie zwracającej model lub wyrzucając wyjątek. –