2012-01-24 2 views
0

У меня есть довольно простое веб-приложение для проверки данных, написанное с помощью ASP MVC, которое имеет два представления одной и той же модели для разных целей.Уменьшение дублирования кода с помощью HTML-помощников

  1. Agent view - Форма, заполненная лицом, проверяющим информацию. Каждое поле на форме в этом виде имеет 3 подполя:

    a. Исходное значение. Значение из базы данных до вызова было выполнено.

    b. Новая стоимость - значение, предоставляемое лицом по телефону, если оно отличается от оригинала.

    c. Действие - общее указание на то, что произошло

  2. QC View - форма, заполненная кем-то, кто рассматривает работу, выполняемую в представлении агента. Каждое поле на форме в этом виде имеет 5 подполей:

    a. Исходное значение - То же, что указано выше

    b. Значение агента - значение, указанное агентом в 1b выше.

    c. Значение QC - исправленное «новое значение», если значение, указанное агентом, неверно.

    d. Агент Действие - То же, что указано выше, кроме только чтения только в этом представлении

    e. Действие КК - исправленное «новое действие», если агент неправильно выбрал его.

Единственные различия между двумя видами являются доступными подполями. Я хотел бы иметь возможность использовать один вид для представления обоих представлений, поскольку общая структура страниц идентична, и просто используйте HTML-помощники для обработки различий в подполях. То, что я до сих пор являюсь 2 отчетливо отдельными серии хелперов (в настоящее время в том же классе, хотя может быть отделен):

// 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

Ваше решение звучит слишком сложно. Какую версию ASP.NET MVC вы используете? – SoWeLie

+0

@SoWeLie - я использую MVC 3. –

ответ

3

Поскольку вы используете MVC3, я рекомендовал бы использовать дочерние действия для подполя:

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

Дети действия позволяют выполнять действия на контроллере внутри вашей точки зрения, это было бы гораздо более чистый подход.

+0

Как это отличается от передачи состояния помощнику? –

+0

Поскольку с дочерним действием вы можете отобразить другой вид. С помощью помощника вы должны объединить разметку внутри функции C#. – SoWeLie

+0

Хорошая точка. Я сделаю это. –

0

Я был в состоянии реализовать (мою интерпретацию) советы, предоставленные @SoWeLie довольно просто. Это было связано с созданием новой модели для размещения надмножества возможных свойств управления и нового представления для каждого набора элементов управления (один для аудита и один для обзора). Проблема с этим было результирующее View API был некрасив:

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

и каждый контроллер действия содержал что-то вроде:

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); 
} 

Helper:

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, ...); 
} 

конечно было около полутора десятков Ot ее итерации между показанными, чтобы помочь ситуации, и никто из них не сделал, насколько это необходимо. Я уверен, что еще есть улучшения, но это то, что у меня есть до сих пор.

Выполнение этого способа предоставляет простой API для использования в представлении без необходимости знать или заботиться о реализации и может удовлетворить все требования моего ранее существовавшего API с незначительной модификацией (в конце на наименее). Я не уверен, является ли это то, что ответ намеревался в результате, но он функциональный и обеспечивает простоту.

Надеюсь, мои головные боли помогут кому-то еще в будущем.

Смежные вопросы