Angela
Angela

Reputation: 3389

Can I move common code from a method into a base controller with MVC4?

I have the following method in five controllers:

    public ActionResult Index(string page, string title) {
        var vm = new BaseViewModel(); 
        vm.Role = GetRoleNumber(User);
        vm.MenuItems = contentService.GetMenuItems("00", vm.Role);
        vm.Menu = pageService.GetMenu(vm.MenuItems, Request.FilePath);

        // difference code here for each controller
    }

All my controllers inherit from a controller called BaseController.

Is there a way I could move this code into my base controller and call it? If so then what would be the best way to implement this?

Upvotes: 1

Views: 1374

Answers (4)

user610217
user610217

Reputation:

You could make an abstract ActionResult method in your base controller:

protected BaseViewModel vm;

public ActionResult Index(string page, string title) {
    vm = new BaseViewModel(); 
    vm.Role = GetRoleNumber(User);
    vm.MenuItems = contentService.GetMenuItems("00", vm.Role);
    vm.Menu = pageService.GetMenu(vm.MenuItems, Request.FilePath);

    try
    {
        return IndexSupplemental();
    }
    catch(NotImplementedException ex)
    {
        // Log and move on; the abstract method is not implemented.
    }

    return View();
}

protected abstract ActionResult IndexSupplemental();

Then every controller would have to implement this abstract method.

Upvotes: 3

Mikael Eliasson
Mikael Eliasson

Reputation: 5227

In my projects most of my actions will return a viewmodel that inherits from the BaseViewModel but there are exceptions to this. So what I did was something like this in ControllerBase:

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        var authData = GetUserData();
        if (authData != null)
        {
            var result = filterContext.Result as ViewResult;
            if (result != null)
            {
                var vm = result.Model as ViewModelBase;
                if (vm != null)
                {
                    vm.UserId = authData.UserID;
                    vm.UserName = User.Identity.Name;
                }
            }

        }
    }

What you could do otherwise, as I expect your ViewModel to be of different types, is to create a method similar to this in ControllerBase:

NOTE This does not do what you want. I'm just showing a technique for creating a new instance of a derived class with some initialization code.

    protected T Command<T>() where T : BaseCommand, new()
    {
        var command = new T();
        command.IP = Request.UserHostAddress;
        if (User != null && User.Identity.IsAuthenticated)
        {

            var authData = GetUserData();
            if (authData != null)
            {
                command.UserId = authData.UserID;

            }
        }
        return command;
    }

Which would be used as

var command = Command<CreateUserCommand>();

Upvotes: 1

Ufuk Hacıoğulları
Ufuk Hacıoğulları

Reputation: 38488

You can move it to a method in your base controller and call it when you need it.

public class BaseController : Controller
{
    protected BaseViewModel _viewModel;

    public void InitializeViewModel() {

        vm = new BaseViewModel(); 
        vm.Role = GetRoleNumber(User);
        vm.MenuItems = contentService.GetMenuItems("00", vm.Role);
        vm.Menu = pageService.GetMenu(vm.MenuItems, Request.FilePath);
    }
}

An example:

public class MyController : BaseController
{
    public ActionResult Index(string page, string title)
    {
        InitializeViewModel();

        DoSomething(_viewModel);
    }
}

Upvotes: 2

Alex Peta
Alex Peta

Reputation: 1407

This is an exact candidate for the Repository Pattern. You could create all of these in your Repository class and call that method in each ActionResult method

public void Repository : IRepository
{
   public GetMyBaseViewModel()
   {
    //..implementation here
   }
}

public interface IRepository
{
  BaseViewModel GetMyBaseViewModel();
}

.... and in your controllers : ...

public class HomeController : Controller
    {
        //private repository member
        private readonly IRepository _repository;

        //controller constructors
        //injecting the repository here
        public HomeController() : this(new Repository()) 
        {

        }
        public HomeController(IRepository repository)
        {
          _repository = repository;
        }

        //methods that call the repository for the vm data context
        public ActionResult Index()
        {
            var vm = _repository.GetMyBaseViewModel();
            return View();
        }
}

Upvotes: 4

Related Questions