Wir fügen unsere Anwendungs- und Geschäftslogik in separate Schichten (csproj-Datei), eine Domänenebene für Geschäftslogik und eine Serviceschicht für Anwendungslogik ein. Dadurch werden sie vollständig vom MVC-Projekt abstrahiert. Das hat zwei große Vorteile für uns. Die erste ist, dass die Geschäftslogik nicht an ein Muster gebunden ist, das sich ändern könnte. Vor ein paar Jahren hätte sich keiner von uns vorstellen können, wie beliebt MVC heute ist, und in ein paar Jahren wissen wir nicht, ob es etwas Neues geben wird, das MVC ersetzen wird und den Großteil Ihres Codes bekommt "Ungebunden" zu MVC würde helfen, sollten Sie jemals MVC für etwas anderes verlassen wollen.
Der zweite Vorteil ist, dass verschiedene Präsentationsebenen sehr einfach zu implementieren sind. Wenn Sie also Ihre Geschäftslogik als WCF-Dienst darstellen möchten, können Sie dies ganz einfach tun, indem Sie ein neues WCF-Projekt erstellen und eine Fassade für Ihre Service- und Domain-Layer erstellen. Das macht die Wartung sehr einfach, da sowohl Ihr MVC-Projekt als auch Ihr WCF-Dienst dieselben Business Logic-Klassen verwenden.
Beispiel Unten ist ein Beispielcode, was ich tun würde. Dies ist schnell und schmutzig, und es sollte wie das Hinzufügen von Protokollierung es mehr sein, wenn der Benutzer nicht zurück in die Datenbank usw. nicht speichern ...
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;
}
}
Ihr Controller nun wie folgt
[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);
}
aussehen würde
Und wenn Sie die Auszahlung in einem Web-Service aussetzen mussten (ich arbeite in einer Unternehmensumgebung, so dass dies für mich viel passiert), tun Sie Folgendes ...
public class MyWCFService : IMyWCFService
{
private PayoutService service = new PayoutService();
public PayoutResult Payout(string username, PayoutModel model)
{
return this.service.Payout(username, model);
}
}
Ich würde empfehlen, all Ihren Code in ein Domänenmodell zu setzen. Es macht den Controller viel sauberer. –
@DarrenDavies Also selbst ModelState.IsValid sollte in das Domänenmodell gelegt werden? –
Nein, 'ModelState.IsValid' ist MVC-Zeugs, ich würde den' if'-Bedingungsteil in die Domäne setzen, um ein Modell zurückzugeben oder eine Ausnahme auszulösen. –