我可以使用MVC4将公共代码从方法移动到基本控制器吗?

时间:2012-09-07 13:45:05

标签: asp.net-mvc asp.net-mvc-3

我在五个控制器中有以下方法:

    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
    }

我的所有控制器都从名为BaseController的控制器继承。

有没有办法可以将此代码移动到我的基本控制器并调用它?如果是这样,那么实现这个的最佳方法是什么?

4 个答案:

答案 0 :(得分:4)

这是存储库模式的精确候选者。 您可以在Repository类中创建所有这些,并在每个ActionResult方法中调用该方法

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

public interface IRepository
{
  BaseViewModel GetMyBaseViewModel();
}

.... 在你的控制器中: ...

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();
        }
}

答案 1 :(得分:3)

您可以在基本控制器中创建一个抽象的ActionResult方法:

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

然后每个控制器都必须实现这种抽象方法。

答案 2 :(得分:2)

您可以将其移动到基本控制器中的方法,并在需要时调用它。

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);
    }
}

一个例子:

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

        DoSomething(_viewModel);
    }
}

答案 3 :(得分:1)

在我的项目中,我的大部分操作都将返回一个从BaseViewModel继承的viewmodel,但是有一些例外。所以我在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;
                }
            }

        }
    }

你可以做的事情,因为我希望你的ViewModel属于不同的类型,就是在ControllerBase中创建一个与此类似的方法:

注意这不符合您的要求。我只是展示了一种使用一些初始化代码创建派生类的新实例的技术。

    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;
    }

将用作

var command = Command<CreateUserCommand>();