使用HTML帮助程序减少代码重复

我有一个用ASP MVC编写的相当简单的数据审计Web应用程序,它有效地为不同目的提供了相同模型的两个视图。

  1. 代理视图 – 由validation信息的人填写的表单。 此视图中表单上的每个字段都有3个子字段:

    一个。 原始值 – 调用之前数据库中的值

    湾 新值 – 如果电话与原始电话不同,则由电话提供的值。

    C。 行动 – 发生事件的一般指示

  2. QC视图 – 由审核代理视图中执行的工作的人填写的表单。 此视图中表单上的每个字段都有5个子字段:

    一个。 原始值 – 与上述相同

    湾 代理值 – 代理商在上面1b中提供的值。

    C。 QC值 – 如果代理指定的值不正确,则更正“新值”。

    d。 代理操作 – 与上面相同,但在此视图中只读

    即 QC行动 – 如果代理人选择不当,则更正“新行动”。

两个视图之间的唯一区别是可用的子字段。 我希望能够使用单个视图来表示两个视图,因为页面的整体结构是相同的,只需使用HTML帮助程序来处理子字段中的差异。 到目前为止我所拥有的是两个截然不同的助手系列(目前属于同一类,但可以分开):

// Agent controls public static MvcHtmlString AuditControl(this HtmlHelper htmlHelper, string id, string fieldLabel, MvcHtmlString editControl, string cssClass) public static MvcHtmlString AuditControl(this HtmlHelper htmlHelper, string id, string fieldLabel, string editControl, string cssClass) public static MvcHtmlString AuditControl(this HtmlHelper htmlHelper, string id, string fieldLabel, string cssClass) where COMPLEX : AbstractComplex, new() // QC controls public static MvcHtmlString ReviewControl(this HtmlHelper htmlHelper, string id, string fieldLabel, MvcHtmlString editControl, string cssClass) public static MvcHtmlString ReviewControl(this HtmlHelper htmlHelper, string id, string fieldLabel, string editControl, string cssClass) public static MvcHtmlString ReviewControl(this HtmlHelper htmlHelper, string id, string fieldLabel, string cssClass) where COMPLEX : AbstractComplex, new() 

第三种实现处理由多个数据组成的更复杂的字段(如全名,地址等)。

我考虑过的一种可能的解决方案是将不同类型的控件分成不同的类,这些类实现了一个公共接口,然后将它们作为类型参数传递给更通用的HTML帮助器。 我认为这会起作用但是我会以某种方式告诉视图它应该使用哪个实现来绘制视图,这似乎有问题,因为它似乎模糊了View和Controller之间的界限。

一个不太吸引人的方法似乎显而易见的是从控制器传递一种管理标志,该标志将由通用(在逻辑而非通用类型通用)工厂助手中使用,并在其中构建逻辑以知道要使用哪一系列方法。 这会使模型和视图保持分离,但感觉很脏,因为HTML帮助程序将不仅仅负责构建HTML。

这是一个合理的情况来打破MVC设计的关注点分离还是有更合适的解决方案?

由于您使用的是MVC3,我建议对子字段使用子操作:

http://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx

子操作允许您在视图内的控制器上执行操作,这将是一种更清晰的方法。

我能够非常简单地实现(我的解释)@SoWeLie提供的建议。 它涉及创建一个新模型来容纳可能的控件属性的超集,并为每个不同的控件集绘制一个新视图(一个用于Audit,一个用于Review)。 它的问题是生成的View API很难看:

 @Html.RenderAction("DrawControl", new { id = "ID" ... }) // Repeated for all of the overloads of DrawControl 

每个Controller动作包含如下内容:

 public ActionResult DrawControl(string id, ...) { // FieldControl being the name of my Model var viewModel = new FieldControl() { ID = id, ... }; if (shouldRenderAudit) return PartialView("AuditControl", viewModel); else return PartialView("ReviewControl", viewModel); 

我无法弄清楚如何让我的通用帮助程序在这种情况下工作,此外,我想删除减少明显的代码重复,所以这很快成为:

 @functions { public string DrawControl(string id, ...) { return Html.Render("DrawControl", new { id = "ID" }); } // Repeated for all of the overloads of DrawControl } @DrawControl("ID", ...) 

使用相同的控制器操作。 这个问题(忽略了View完全具有function的事实)是@functions块必须包含在任何想要使用它们的视图中(目前只有2个但很快就会气球到5和谁知道我的前任会对此做些什么呢? 我再次快速重新编写代码,这次是为了恢复帮助程序(通常保持视图,模型和控制器的更改),最后结束了这个:

视图:

 @(Html.DrawComplexControl("id", ...)) @Html.DrawSimpleControl("id", ...) 

控制器:

 // One common action that is used to determine which control should be drawn public ActionResult DrawControl(FieldControl model) { if (shouldRenderAudit) return PartialView("AuditControl", model); else return PartialView("ReviewControl", model); } 

帮手:

 public static MvcHtmlString DrawControl(this HtmlHelper htmlHelper, string id, ...) { var model = new FieldControl() { ID = id, ... }; return htmlHelper.Action("DrawControl", model); } public static MvcHtmlString DrawSimpleControl(this HtmlHelper htmlHelper, string id, ...) { return DrawSimpleControl(htmlHelper, id, ...); } public static MvcHtmlString DrawSimpleControl(this HtmlHelper htmlHelper, string id, ...) { // Set some defaults to simplify the API return DrawControl(htmlHelper, id, ...); } public static MvcHtmlString DrawComplexControl(this HtmlHelper htmlHelper, string id, ...) where T : AbstractComplex, new() { // Build the required controls based on `T` return DrawControl(htmlHelper, id, ...); } 

当然,在显示的情况之间有大约六个其他迭代来帮助这种情况,并且没有一个在必要的范围内进行。 我确信还有待改进,但这是我到目前为止所做的。

这样做可以为View提供一个非常简单的API,无需知道或关心实现,它只需要很小的修改就可以满足我原有API的所有要求(至少到目前为止)。 我不确定这是否是答案的结果,但它是function性的,并提供了必要的简单性。

希望我的头痛将来会帮助别人。