asp.net-mvc 如何继承 ASP.NET MVC 控制器并仅更改视图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1567084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I inherit an ASP.NET MVC controller and change only the view?
提问by Bret Walker
I have a controller that's inheriting from a base controller, and I'm wondering how I can utilize all of the logic from the base controller, but return a different view than the base controller uses.
我有一个继承自基本控制器的控制器,我想知道如何利用基本控制器的所有逻辑,但返回与基本控制器使用的视图不同的视图。
The base controller populates a model object and passes that model object to its view, but I'm not sure how I can access that model object in the child controller so that I can pass it to the child controller's view.
基本控制器填充一个模型对象并将该模型对象传递给它的视图,但我不确定如何在子控制器中访问该模型对象,以便我可以将它传递给子控制器的视图。
采纳答案by Bret Walker
Based on the feedback given on this thread, I've implemented a solution like the one proposed by Antony Koch.
根据在此线程上给出的反馈,我实施了一个类似于 Antony Koch 提出的解决方案。
Instead of using an abstract method, I used a concrete, virtual GetIndex method so that I could put logic in it for the base controller.
我没有使用抽象方法,而是使用了一个具体的、虚拟的 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);
}
}
回答by G-Wiz
A couple points. You can type your return value as ViewResult if you know that's all you're going to return. Then you can interrogate that value from the overridden implementation. More importantly, according to the MVC v1 source, calling View(object) simply sets the ViewData.Model on the controller, then constructs a ViewResult.
几点。如果您知道这就是您要返回的全部内容,则可以将返回值键入为 ViewResult。然后您可以从覆盖的实现中查询该值。更重要的是,根据MVC v1源码,调用View(object)只是在控制器上设置了ViewData.Model,然后构造了一个ViewResult。
Controller.cs:440
控制器.cs:440
protected internal ViewResult View(object model) {
return View(null /* viewName */, null /* masterName */, model);
}
Controller.cs:456
控制器.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
};
}
So all you need to do is call the base method and call View(string).
所以你需要做的就是调用基本方法并调用 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");
}
}
Of course you waste CPU cycles constructing the ViewResult that you ignore. So instead you can do this:
当然,您浪费 CPU 周期来构建您忽略的 ViewResult。所以你可以这样做:
public class CoolController : BaseControllers.CoolController
{
public override ViewResult Get()
{
var baseResult = base.Get();
baseResult.ViewName = "NotGet";
return baseResult;
}
}
If your base controller returns ActionResult, you'll have to cast it to ViewResult before changing the ViewName.
如果您的基本控制器返回 ActionResult,则必须在更改 ViewName 之前将其转换为 ViewResult。
回答by LukLed
Sample from my app:
来自我的应用程序的示例:
Base class:
基类:
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());
}
Inherited:
遗传:
public class SeverityController : BaseTableController<Severity, ISeverityService>
{
public SeverityController(ISeverityService service)
: base(service)
{
}
//NO CODE INSIDE
}
SeverityController.Index() leads to Views/Severity/Index.aspx. Just had to prepare view. Severity is one of dictionared in my bug tracking application. Every dictionary has similar logic, so I could share some code.
SeverityController.Index() 导致 Views/Severity/Index.aspx。只好准备视图。严重性是我的错误跟踪应用程序中的一种。每个字典都有相似的逻辑,所以我可以分享一些代码。
回答by Bret Walker
I ended up just putting an extra parameter on the base Controller -- viewName.
我最终只是在基本控制器上放置了一个额外的参数——viewName。
Seems to work just fine.
似乎工作得很好。
Am I missing any major downsides?
我是否遗漏了任何主要缺点?
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");
}
}
回答by Antony Koch
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");
}
}
}
Just use abstraction to call the bits you need from the sub-classes.
只需使用抽象从子类中调用所需的位即可。

