We put our application and business logic in separate layers (csproj file) for the domain level for business logic and the service level for application logic. This completely abstracts them from the MVC project. This has two big advantages for us. First, business logic is not tied to a template that can change. A few years ago, none of us would have seen the popularity of MVC today, and in a few years we don’t know if there will be anything new that will come and replace MVC, so the vast majority of your code will be “un-tied” for MVC someday want to give up MVC for something else.
The second advantage is that it is very easy to implement different levels of presentation. Therefore, if you want to present your business logic as a WCF service, you can do this very easily by creating a new WCF project and making this facade for your service level and domain. This simplifies maintenance because both your MVC project and your WCF service will use the same business logic classes.
Example The following is an example code of what I will do. This is quick and dirty, and there should be more to it than adding registrations if the user does not save back to the database, etc.
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; }
Your controller will now look like this:
[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); }
And if you need to expose the payment in a web service (I work in a corporate environment, so this is very common for me). You do the following ...
public class MyWCFService : IMyWCFService { private PayoutService service = new PayoutService(); public PayoutResult Payout(string username, PayoutModel model) { return this.service.Payout(username, model); } }