【发布时间】:2009-10-14 15:28:05
【问题描述】:
我有一个从基本控制器继承的控制器,我想知道如何利用基本控制器的所有逻辑,但返回与基本控制器不同的视图。
基本控制器填充一个模型对象并将该模型对象传递给它的视图,但我不确定如何在子控制器中访问该模型对象,以便将它传递给子控制器的视图。
【问题讨论】:
-
您是否尝试仅从基本控制器继承并准备视图?
标签: asp.net-mvc
我有一个从基本控制器继承的控制器,我想知道如何利用基本控制器的所有逻辑,但返回与基本控制器不同的视图。
基本控制器填充一个模型对象并将该模型对象传递给它的视图,但我不确定如何在子控制器中访问该模型对象,以便将它传递给子控制器的视图。
【问题讨论】:
标签: asp.net-mvc
几点。如果您知道这就是您要返回的全部内容,则可以将返回值键入为 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。
【讨论】:
我的应用示例:
基类:
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。只需要准备视图。严重性是我的错误跟踪应用程序中的字典之一。每个字典都有类似的逻辑,所以我可以分享一些代码。
【讨论】:
根据此线程上给出的反馈,我实施了一个类似于 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);
}
}
【讨论】:
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");
}
}
只需使用抽象从子类中调用您需要的位。
【讨论】:
我最终只是在基本控制器上添加了一个额外的参数——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");
}
}
【讨论】: