【问题标题】:How can I inherit an ASP.NET MVC controller and change only the view?如何继承 ASP.NET MVC 控制器并仅更改视图?
【发布时间】:2009-10-14 15:28:05
【问题描述】:

我有一个从基本控制器继承的控制器,我想知道如何利用基本控制器的所有逻辑,但返回与基本控制器不同的视图。

基本控制器填充一个模型对象并将该模型对象传递给它的视图,但我不确定如何在子控制器中访问该模型对象,以便将它传递给子控制器的视图。

【问题讨论】:

  • 您是否尝试仅从基本控制器继承并准备视图?

标签: asp.net-mvc


【解决方案1】:

几点。如果您知道这就是您要返回的全部内容,则可以将返回值键入为 ViewResult。然后,您可以从覆盖的实现中查询该值。更重要的是,根据 MVC v1 源码,调用 View(object) 只是在控制器上设置 ViewData.Model,然后构造一个 ViewResult。

Controller.cs:440

protected internal ViewResult View(object model) {
    return View(null /* viewName */, null /* masterName */, model);
}

Controller.cs:456

protected internal virtual ViewResult View(string viewName, string masterName, object model) {
    if (model != null) {
        ViewData.Model = model;
    }

    return new ViewResult {
        ViewName = viewName,
        MasterName = masterName,
        ViewData = ViewData,
        TempData = TempData
    };
}

所以你需要做的就是调用基础方法并调用 View(string)。

namespace BaseControllers
{
    public class CoolController
    {
        public virtual ViewResult Get() 
        {
            var awesomeModel = new object();
            return View(awesomeModel);
        }
    }
}

public class CoolController : BaseControllers.CoolController
{
    public override ViewResult Get() 
    {
        var ignoredResult = base.Get();
        // ViewData.Model now refers to awesomeModel
        return View("NotGet");
    }
}

当然,您会浪费 CPU 周期来构建您忽略的 ViewResult。因此,您可以这样做:

public class CoolController : BaseControllers.CoolController
{
    public override ViewResult Get() 
    {
        var baseResult = base.Get();
        baseResult.ViewName = "NotGet";
        return baseResult;
    }
}

如果您的基本控制器返回 ActionResult,您必须在更改 ViewName 之前将其强制转换为 ViewResult。

【讨论】:

    【解决方案2】:

    我的应用示例:

    基类:

    public abstract class BaseTableController<T,TU> : BaseController where TU : IGenericService<T>,IModelWrapperService
    {
        protected readonly TU _service;
    
        public BaseTableController(TU service)
        {
            _service = service;
            _service.ModelWrapper = new ControllerModelStateWrapper(ModelState);
        }
    
    
        public ActionResult Index()
        {
            return View(_service.List());
        }
    

    继承:

    public class SeverityController : BaseTableController<Severity, ISeverityService>
    {
        public SeverityController(ISeverityService service)
            : base(service)
        {
        }
    
       //NO CODE INSIDE
    }
    

    SeverityController.Index() 导致 Views/Severity/Index.aspx。只需要准备视图。严重性是我的错误跟踪应用程序中的字典之一。每个字典都有类似的逻辑,所以我可以分享一些代码。

    【讨论】:

      【解决方案3】:

      根据此线程上给出的反馈,我实施了一个类似于 Antony Koch 提出的解决方案。

      我没有使用抽象方法,而是使用了具体的虚拟 GetIndex 方法,这样我就可以在其中为基本控制器添加逻辑。

      public class SalesController : Controller
      {
          // Index view method and model
          public virtual ActionResult GetIndex()
          {
               return View("Index", IndexModel);
          }
          protected TestModel IndexModel { get; set; }
      
          public virtual ActionResult Index()
          {
              ViewData["test"] = "Set in base.";
      
              IndexModel = new TestModel();
              IndexModel.Text = "123";
      
              return GetIndex();
          }
      
          [AcceptVerbs(HttpVerbs.Post)]
          public virtual ActionResult Index(TestModel data, FormCollection form)
          {
              TryUpdateModel(data, form.ToValueProvider());
              IndexModel = data;
      
              return GetIndex();
          }
      }
      
      // This class will need to be in a different namespace or named differently than the
      // parent controller
      public class SalesController : MyApp.Controllers.BaseControllers.SalesController
      {
          // Index view method and model
          public override ActionResult GetIndex()
          {
              return View("ClientIndex", IndexModel);
          }
      
          public override ActionResult Index()
          {
              return base.Index();
          }
      
          [AcceptVerbs(HttpVerbs.Post)]
          public override ActionResult Index(TestModel data, FormCollection form)
          {
              return base.Index(data, form);
          }
      }
      

      【讨论】:

      • 我也遇到了同样的问题,谁能帮帮我? My Question
      • 现在您只需为子控制器创建一个新文件夹,子控制器的操作方法就会出现在该文件夹中。
      【解决方案4】:
      public class BaseController : Controller {
      protected BaseController() {}
      
      public ActionResult Index()
      {
          return GetIndex();
      }
      
      public abstract ActionResult GetIndex();  }
      
      public class MyController : BaseController {
      public MyController() {}
      
      public override GetIndex()
      {   
          return RedirectToAction("Cakes","Pies");
      } 
      

      }

      只需使用抽象从子类中调用您需要的位。

      【讨论】:

      • 我做了类似的事情。请参阅我的新答案。我希望避免为每个控制器操作创建辅助方法,但我想这是最好的方法。
      【解决方案5】:

      我最终只是在基本控制器上添加了一个额外的参数——viewName。

      似乎工作得很好。

      我是否遗漏了任何主要缺点?

      public class SalesController : Controller
      {
          public virtual ActionResult Index(string viewName)
          {
              ViewData["test"] = "Set in base.";
      
              TestModel model = new TestModel();
              model.Text = "123";
      
              return String.IsNullOrEmpty(viewName) ? View(model) : View(viewName, model);
          }
      
          [AcceptVerbs(HttpVerbs.Post)]
          public virtual ActionResult Index(TestModel data, FormCollection form, string viewName)
          {
              TryUpdateModel(data, form.ToValueProvider());
              return String.IsNullOrEmpty(viewName) ? View(data) : View(viewName, data);
          }
      }
      
      public class SalesController : MyApp.Controllers.BaseControllers.SalesController
      {
          public override ActionResult Index(string viewName)
          {
              return base.Index("ClientIndex");
          }
      
          [AcceptVerbs(HttpVerbs.Post)]
          public override ActionResult Index(TestModel data, FormCollection form, string viewName)
          {
              return base.Index(data, form, "ClientIndex");
          }
      }
      

      【讨论】:

      • 我担心的是用户可以通过 http 将参数发送到控制器中的 ActionResult。您冒着用户能够在不覆盖“索引”的控制器上调用索引的风险,从而能够传递具有意外结果的 viewName。不太可能,但仍有可能。
      • 我不喜欢这个解决方案。您不必指定视图名称。想象一下,您有一个 BaseController 和两个继承 - ChildOneController 和 ChildTwoController。如果您调用 ~/ChildOne/Index,它将从 ~/ChildOne/Index/Index.aspx 获取视图。如果您调用 /ChildTwo/Index,它将从 ~/ChildTwo/Index/Index.aspx 获取视图。视图名称相同,但取自不同的地方。
      • 我也遇到了同样的问题,谁能帮帮我? My Question
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-26
      相关资源
      最近更新 更多