MVC architectural question - Where should payment processing go?
This question is related to my ASP.NET MVC 2 development, but it could apply to any MVC environment and a question of where the logic should go.
So let's say I have a controller that takes an online payment开发者_StackOverflow社区 such as a shopping cart application. And I have the method that accepts the customers' credit card information:
public class CartController : Controller
CartRepository cartRepository = new CartRepository()
[HttpPost]
public ActionResult Payment(PaymentViewModel rec)
{
if(!ModelState.IsValid)
{
return View(rec);
}
// process payment here
return RedirectToAction("Receipt");
}
At the comment process payment here
should the payment processing be handled:
- In the controller?
- By the repository?
- Someplace else?
You want 3. Someplace else.
Put this in a class library. Create an interface that has all the methods required for the payment processing. Make the methods generic. Put the specifics in the implementation of the interface. Then derive your payment processing service from that interface. This give you options that include testing and multiple payment processors.
Look at the MVC Storefront videos at http://www.asp.net/learn/mvc-videos/. Probably video #23 (part 22). It's been a while since I viewed these.
I would recommended building out this logic in a Business Object and calling that from your Controller.
For instance create a PaymentBO class (static or otherwise) so you could call PaymentBO.ProcessPayment(...)
The Model
should handle this, as it is the component that is tasked with working directly with (and maintaining the consistency of) your data. Specifically:
The model is the domain-specific representation of the data upon which the application operates.
If you're using the repository pattern, then I'd suggest creating a service object to handle any payments, and have your controller call this.
That is an architectural question. You should decide, for the whole system, which approach to implementing business logic is the right one for your particular scenario. The approaches are best described (in my opinion) in Martin Fowlers PoEAA. There are three main patterns:
- transaction script - means having a separate object for processing a particular transaction
- active record - means having simple logic placed directly on O/RM-mapped table-representing objects
- domain model - means having rich code-only model which is responsible for solving the problem
To choice depends mainly on your system complexity level. The patterns I described are ordered by their potential to solve complex problems (DDD is best at really complex stuff, but also by itself introduce some 'accidental' complexity).
Since there is already references on the repository pattern, you may elaborate on to Domain Driven Design (as mentioned by Szymon).
If you do, you will want a Service Layer which in turn talks to the rich model underneath it. Here is the pseudo code
On the Payment Controller:
var paymentDetails = mapFromViewModel(rec)
PaymentService.Pay(paymentDetails)
On the Payment Service
void Pay (PaymentDetails paymentDetails)
{
// leverage on rich model behavior here
if (User.IsHaveEnoughMoney)
{
Cashier.Pay( ... )
}
// more ...
}
精彩评论