views:

181

answers:

6

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 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:

  1. In the controller?
  2. By the repository?
  3. Someplace else?
+1  A: 

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(...)

hunter
+1  A: 

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.

Justin Ethier
The model is just the object passed to the view. I don't think biz logic should sit on the model. That said, I've seen it a hundred times before...
hunter
@Hunter Business logic shouldn't be in your *view model*, but it should go in your domain model if you have one.
Ryan
I would disagree, if you consider that most Models are nothing more than Domain object anyways (ASP.NET MVC kind of blurs the two and it's frustrating). I try to keep my Domain objects (for instance objects representing data tables) and my Model objects (could be a Domain object or a collection of Domain objects or whatever) as clean as possible and use BO's for this type of thing...
hunter
If your domain objects have no behavior, you're losing out on the primary value of an mvc design because it is the easiest way to localize application concerns. You'll end up with an Anemic Domain and either top heavy views or convoluted behavior. That being said, I would prefer to extract an interface for talking to the Payment Service and have the controller pass an injected instance of it domain or adapter objects for the payment gateway you are working with.
JasonTrue
I guess it just comes down to personal preference and patterns.
hunter
+1  A: 

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.

Paddy
+6  A: 

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.

37Stars
@37Stars. These videos are good. Thanks for pointing me there.
Keltex
+1  A: 

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).

Szymon Pobiega
+1  A: 

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 ...

}
ronaldwidha