如何继承 ASP.NET MVC 控制器并仅更改视图?
Posted
技术标签:
【中文标题】如何继承 ASP.NET MVC 控制器并仅更改视图?【英文标题】:How can I inherit an ASP.NET MVC controller and change only the view? 【发布时间】:2009-10-14 15:28:05 【问题描述】:我有一个从基本控制器继承的控制器,我想知道如何利用基本控制器的所有逻辑,但返回与基本控制器不同的视图。
基本控制器填充一个模型对象并将该模型对象传递给它的视图,但我不确定如何在子控制器中访问该模型对象,以便将它传递给子控制器的视图。
【问题讨论】:
您是否尝试仅从基本控制器继承并准备视图? 【参考方案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以上是关于如何继承 ASP.NET MVC 控制器并仅更改视图?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过更改 ASP.NET MVC 中的 Url 来阻止对控制器的访问?