我有一个用ASP MVC编写的相当简单的数据审计Web应用程序,它有效地为不同目的提供了两个相同模型的视图。
代理视图 - 由验证信息的人填写的表单。此视图中表单上的每个字段都有3个子字段:
一个。原始值 - 调用之前数据库中的值
湾新值 - 如果电话号码与原始电话号码不同,则该电话号码提供的值。
℃。行动 - 发生了什么的一般指示
QC View - 由审核代理视图中执行的工作的人填写的表单。此视图中表单上的每个字段都有5个子字段:
一个。原始值 - 与上述相同
湾代理值 - 代理商在上面提供的值。
℃。 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<COMPLEX>(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<COMPLEX>(this HtmlHelper htmlHelper, string id, string fieldLabel, string cssClass) where COMPLEX : AbstractComplex, new()
第三种实现处理由多个数据组成的更复杂的字段(如全名,地址等)。
我考虑过的一种可能的解决方案是将不同类型的控件分成不同的类,这些类实现了一个公共接口,然后将它们作为类型参数传递给更通用的HTML帮助器。我认为这会起作用但是我会以某种方式告诉视图它应该使用哪个实现来绘制视图,这似乎有问题,因为它似乎模糊了View和Controller之间的界限。
一个不太吸引人的方法似乎显而易见的是从控制器传递一种管理标志,该标志将由通用(在逻辑而非通用类型通用)工厂助手中使用,并在其中构建逻辑以了解哪一系列方法使用。这会使模型和视图保持分离,但感觉很脏,因为HTML帮助程序不仅仅负责构建HTML。
这是一个合理的情况来打破MVC设计的问题分离还是有更合适的解决方案?
答案 0 :(得分:3)
由于您使用的是MVC3,我建议对子字段使用子操作:
http://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx
子操作允许您在视图内的控制器上执行操作,这将是一种更清晰的方法。
答案 1 :(得分:0)
我能够非常简单地实现(我的解释)@SoWeLie提供的建议。它涉及创建一个新模型来容纳可能的控件属性的超集,并为每个不同的控件集绘制一个新视图(一个用于审计,一个用于审阅)。它的问题是生成的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完全具有函数的事实)是@functions
块必须包含在任何想要使用它们的视图中(目前只有2个但很快就会气球化)到5,谁知道我的前任会对此做些什么)。我再次快速重新编写代码,这次是为了恢复帮助程序(通常保持视图,模型和控制器的更改),最后结束了这个:
查看:
@(Html.DrawComplexControl<ProviderName>("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<T>(this HtmlHelper htmlHelper, string id, ...) where T : AbstractComplex, new()
{
// Build the required controls based on `T`
return DrawControl(htmlHelper, id, ...);
}
当然,在显示的情况之间有大约六个其他迭代来帮助这种情况,并且没有一个在必要的范围内进行。我确信还有待改进,但这是我到目前为止所做的。
这样做提供了一个非常简单的API供View使用,而不必知道或关心实现,它只需要很小的修改即可满足我原有API的所有要求(最后至少)。我不确定这是否是答案的结果,但它是功能性的,并提供了必要的简单性。
希望将来我的头痛会帮助别人。