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); %>
Я могу передать модель непосредственно со страницы выставления счетов и доставки, потому что класс напрямую сходит с адреса. До тех пор, пока логика будет правильно обрабатывать адреса, вам не придется делать много изменений в контроллере, если таковые имеются.