22

I understand MVC is all about putting things in the correct place and the logic where it should be. My controller actions are getting filled up with business logic (not related to data storage) and I feel that I should start moving some of the logic to a different place.

Is there a convention for where I should place this logic? For example I have the following controller that's located in the controllers file:

adminPowerController 

  public ActionResult Create(string test1)
    // business logic
    // business logic
    // business logic
    return View();
  }
  public ActionResult Index(string test1)
    // business logic
    // business logic
    // business logic
    return View();
  }
Geraldo
  • 335
  • 3
  • 6

3 Answers3

28

The recommended place to put business logic is into a service layer. So you could define an interface which will represent the business operation:

public interface IMyService
{
    DomainModel SomeOperation(string input);
}

and then have an implementation of this service. Finally the controller will use it:

public class MyController: Controller
{
    private readonly IMyService _service;
    public class MyController(IMyService service)
    {
        _service = service;
    }

    public ActionResult Create(string input)
    {
        var model = _service.SomeOperation(input);
        var viewModel = Mapper.Map<DomainModel, ViewModel>(model);
        return View(viewModel);
    }
}

and configure your DI framework to pass the proper implementation of the service into the controller.

Remark: In the example I provided I used AutoMapper to convert between a domain model into a view model which is passed to the view.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 2
    this code has and AutoMapper dependecy so the OP may need to know about that reference – stack72 Jun 14 '11 at 09:52
  • 1
    @stack72, good point. I've updated my answer to provide a reference. – Darin Dimitrov Jun 14 '11 at 09:53
  • Thanks for your feedback. What are the file and directory naming conventions that you use for your service layer? Can I assume you keep these files in a directory called Interfaces? – Geraldo Jun 14 '11 at 09:58
  • @Geraldo, my service layer is usually in a separate project (assembly). I use directories such as Services, Repositories, ... – Darin Dimitrov Jun 14 '11 at 09:59
5

What i tend to do in my MVC projects is to keep as much of the business logic as possible outside of my actions so that I can test them

In some cases I create a service layer and then use that

public class QuizRunner : IQuizRunner
{
    private readonly IServiceProxyclient _quizServiceProxy;
    public QuizRunner(IServiceProxyclient quizServiceProxy)
    {
        _quizServiceProxy = quizServiceProxy;
    }

    public GameCategory GetPrizeGameCategory(int prizeId)
    {
        return _quizServiceProxy.GetGameCategoryForPrizeId(prizeId);
    }

}

public interface IQuizRunner
{
    GameCategory GetPrizeGameCategory(int prizeId);
}



private IQuizRunner_serviceClass;

public AdminPowercontroller(IQuizRunner serviceClass)
{
    _serviceClass = serviceClass;
}


public ActionResult Create(string test1)
    var itemsFromLogic = _serviceClass.Method1();
    return View();
}
public ActionResult Index(string test1)
    var gameCategory = _serviceClass.GetPrizeGameCategory(test1);
    var viewModel = Mapper.Map<GameCategory, GameCategoryViewModel>(gameCategory);
    return View(viewModel);
}

this allows my actions to be tested separately from my service layer and without dependency

Hope this helps

Paul

stack72
  • 8,198
  • 1
  • 31
  • 35
  • Thanks for your feedback. What are the file and directory naming conventions that you use for your service layer? If you don't mind could you show me what a typical file that contains a class implementing IServiceLayerClass would look like. Just the shell of the file and maybe an argument that gets passed in or out. Thanks very much. – Geraldo Jun 14 '11 at 10:00
  • I have updated my answer to show an example service layer class - this class interacts with a webservice but demonstrates the proof of concept – stack72 Jun 14 '11 at 10:07
  • @stack72 - How does the controller get called with the correct service class? – Geraldo Jun 14 '11 at 10:16
  • I have updated my answer to show that the Index action can call my QuizRunner service layer class and then get a specified domain object from my service - I would then map it (using AutoMapper as @ Darin Dimitrov mentioned) to create my View Model and then pass that to the View – stack72 Jun 14 '11 at 10:22
  • @stack72 - While my project is small is there a simpler way to provide the service class to the constructor. Are the classes in the service layer static classes? – Geraldo Jun 14 '11 at 11:22
  • You can certainly not go down the DI route and have a private ServiceLayerClass serviceClass = new ServiceLayerClass(); declaration and use that - this would cut down the need to use DI - if possible try and separate the Service layer logic from the controller logic - its good practice – stack72 Jun 14 '11 at 11:24
1

Business logic should live in your domain model separated from MVC framework and other stuff.

Real world example...

Application (one of my domain entities) controller:

[HttpPost]
public ActionResult Withdraw(int applicationId){
  //find it from repository or whatever
  var app=FindApplication(applicationId);
  //force it do do stuff
  a.Withdraw();
  //send back some response
  return RedirectToAction("Application",new{applicationId});
}

Application entity itself:

public class Application{
 public void Withdraw(){
  //check if current user is authorized to withdraw applications
  Authorize<CanWithdrawApplications>();
  //check if application itself can be withdrawn
  ThrowIf(!CanBeWithdrawn(),"Application can't be withdrawn.");
  //apply state changes
  IsWithdrawn=true;
  //raise domain event
  Raise(new Withdrawn(this));
 }
 public bool CanBeWithdrawn(){
   return !IsWithdrawn && !Project.Contract.IsSigned;
 }
}

For more about this You might want to check out what domain driven design is about.

Community
  • 1
  • 1
Arnis Lapsa
  • 45,880
  • 29
  • 115
  • 195
  • @Amis - So do you normally put the application entity into some kind of service directory? How does FindApplication work? – Geraldo Jun 14 '11 at 11:24
  • @Geraldo My application entity lives in separate assembly called `Domain` (that knows about .Net framework only), folder `Model`. FindApplication just calls NHibernate directly. – Arnis Lapsa Jun 14 '11 at 12:45
  • but if the dao is used in the logic layer,should i inject daoservice in model ? – 王奕然 Sep 28 '14 at 06:31