ASP.NET MVC: хорошая замена для пользовательского контроля?

Я обнаружил, что пользовательские элементы управления невероятно полезны при работе с веб-форматами ASP.NET. Инкапсулируя код, необходимый для отображения элемента управления с разметкой, создание повторно используемых компонентов было очень простым и очень, очень полезным.

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

Мне нужно включить компоненты, похожие на пользовательские элементы веб-форм, на весь сайт, но не для всего сайта, а не на уровне, который принадлежит главной странице. Эти компоненты должны иметь собственный код не только разметки (для взаимодействия с бизнес-слоем), и было бы замечательно, если бы диспетчер страниц не нуждался в информации об элементе управления. Поскольку пользовательские элементы управления MVC не имеют кода, я не вижу хорошего способа сделать это.

Обновление НАКОНЕЦ, хороший (и, ретроспективный, очевидный) способ достичь этого.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace K.ObjectModel.Controls
{
    public class TestControl : ViewUserControl
    {
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            writer.Write("Hello World");
            base.Render(writer);
        }
    }
}

Создайте новый класс, который наследует ViewUserControl

Переопределите метод .Render(), как показано выше.

Зарегистрируйте элемент управления через связанный с ним ASCX, как и в webForm:

<%@ Register TagName="tn" TagPrefix="k" Src="~/Views/Navigation/LeftBar.ascx"%>

Используйте соответствующий тег на любом видном или главном страницах, который вам нужен:

<k:tn runat="server"/>

Убедитесь, что ваш .ascx наследует ваш новый элемент управления:

<%@ Control Language="C#" Inherits="K.ObjectModel.Controls.TestControl" %>

Войля, ты в движении. Это проверено с помощью ASP.NET MVC 2, VS 2010 и .NET 4.0.

Ваш собственный тег ссылается на частичный вид ascx, который наследуется от класса TestControl. Затем элемент управления переопределяет метод Render(), который вызывается для визуализации представления, что дает вам полный контроль над процессом из тега для вывода.

Разница между использованием этого подхода и вызовом Html.RenderPartial() или `Html.RenderAction() 'заключается в добавлении элемента управления в представление выполняется с помощью тега в виде webforms, который не только более удобен для дизайнеров, но и сохраняет их от необходимости знать имена и методы контроллера. Имя класса управления изолировано от ASCX, что также облегчает их удаление в сборке и повторное использование в разных проектах.

Некоторые могут сказать, что это нарушает SoC, но я считаю, что этот подход функционально эквивалентен привязке частичного представления и контроллера вместе при сохранении чистой разметки. Однако должно быть ясно, что разработчику по-прежнему принадлежит только логика, связанная с представлением, в управлении. Логика доступа к данным и доступа к данным все еще принадлежит к их соответствующим уровням.

Ответ 1

На первый взгляд его легко удалить MVC, поскольку он не обладает возможностями для многоразовых компонентов.

Как только вы узнаете ASP.NET MVC, вы найдете несколько методов создания богатых элементов управления и компонентов и инкапсулирующие аспекты MVC следуйте по тем же путям, что и инкапсуляция приложения WebForms.

Я думаю, что вы делаете только просмотр аспектов MVC, а не то, как все базовые M и C могут быть инкапсулированы и связаны друг с другом. Частичные представления, Render Action/Partial - это лишь небольшие части возможностей компонента MVC для базового компонента. Под крышками гораздо больше богатства.

Ответ 2

Я немного запутался здесь.

Прежде всего,.NET MVC, эквивалентный пользовательским элементам управления, Частичные виды. Частичные представления - удобный способ инкапсуляции общей функции View в одном месте. Затем вы можете вызвать частичный вид из другого представления.

Во-вторых, изменение вида не должно означать также изменение контроллера. Если вам необходимо внести изменения в оба только потому, что ваш вид изменился (а не базовые данные), тогда там возникает проблема с кодом где-то вдоль линии.

Ответ 3

a пользовательский элемент управления - это просто материал, который отображает html, в mvc у вас есть html-помощники и частичные представления и обычные представления (вы можете визуализировать их с помощью renderaction)

Html.Helper("someStuff")
Html.RenderPartial("viewname")
Html.RenderAction<Controller>(o => o.Action());

так что в основном это просто помощники

вы можете легко заменить вызов

Html.TextBoxFor(o => o.Name);

с

Html.RenderPartial("textbox", Model.Name);

Ответ 4

Рассмотрим следующий пример:

  • My view (CustomerDetail.ascx) привязывается к модели представления ICustomerDetail, которая выглядит следующим образом:

    интерфейс ICustomerDetail {
      string Имя {get; }
      Адрес CurrentAddress {get; }
    }

  • Я могу создать частичное представление Address.ascx, которое привязывается к модели представления IAddress

  • Когда я создаю CustomerDetail.ascx, я могу поместить Address.ascx на одну и ту же поверхность и привязать его к полю oCustomerDetail.Address

  • IMO - мы должны составлять представления из нескольких таких небольших частичных представлений в MVC, и здесь вы увидите повторное использование и полномочия пользовательских элементов управления (частичные представления)

  • Теперь, если мой контроллер возвращает ICustomerDetail, я смогу повторно использовать Address.ascx без проблем

НТН.

Ответ 5

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

Итак, для дополнительной иллюстрации ваш класс адресов выглядит примерно так:

public class Address
{
    public string StreetAddress { get; set; }
    public string City { get; set; }
    ...
}

Ваш класс регистрации:

public class UserReg
{
    public string UserName { get; set; }
    public Address MailingAddress { get; set; }
    ...
}

Ваши адреса фактуры и доставки могут сходить из класса Address:

public class BillingAddress : Address
{ 
    ...
}

public class ShippingAddress : Address
{ 
    ...
}

В следующих примерах я предполагаю, что вы добавили System.Web.Mvc в раздел namespaces web.config. Основываясь на этой иерархии классов, ваш пользовательский элемент управления будет иметь тег управления, который относится только к классу Address:

<%@ Control Language="C#" Inherits="ViewUserControl<Address>" %>

Поскольку вы это сделали, вам просто нужно передать соответствующую ссылку на эту страницу со страницы. На странице "Регистрация пользователя":

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage<UserReg>" %>
    ...
    <% Html.RenderPartial("AddressControl", Model.MailingAddress); %>

На странице адреса фактуры:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage<BillingAddress>" %>
    ...
    <% Html.RenderPartial("AddressControl", Model); %>

На странице адреса доставки:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage<ShippingAddress>" %>
    ...
    <% Html.RenderPartial("AddressControl", Model); %>

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