MVC - объект множественного строгого типа ... в одном представлении - PullRequest
1 голос
/ 25 октября 2010

После стольких лет использования ASP.Net я все еще пытаюсь понять, как добиться тех же результатов с помощью MVC.

У меня есть materpage с элементом управления, который строго для чего-то типа. Когда я перехожу к представлению другой модели строго типа ... и нажимаю кнопку, чтобы выполнить что-то, я получаю «Элемент модели, переданный в словарь, имеет тип Site.Models.RegisterModel ', но для этого словаря требуется модель элемент типа Site.Models.LogOnModel '".

В этом примере мы можем взять приложение MVC по умолчанию, которое поставляется с VS 2010, давайте представим, что я хочу изменить «LogonUserControl.ascx», чтобы он либо сообщал мне зарегистрированному пользователю (как он работает в настоящее время) ) ИЛИ позвольте мне войти в систему оттуда, показывая мне текстовые поля для имени пользователя и пароля (следовательно, в этом случае с домашней страницы).

Поэтому я беру управление и строго набираю его как:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Gioby.Models.LogOnModel>" %>
<%
    if (Request.IsAuthenticated) {
%>
        Welcome <b><%: Page.User.Identity.Name  %></b>
        [ <%: Html.ActionLink("Log Off", "LogOff", "Account")%> ]
<%
    }
    else {
%> 
    <% using (Html.BeginForm()) { %>
        <div id="logon">
                <div class="editor-label">
                    <%: Html.LabelFor(m => m.UserName)%>
                    <%: Html.TextBoxFor(m => m.UserName)%>
                    <%: Html.ValidationMessageFor(m => m.UserName, "*") %>
                    <%: Html.LabelFor(m => m.Password)%>
                    <%: Html.PasswordFor(m => m.Password)%>
                    <%: Html.ValidationMessageFor(m => m.Password, "*") %>
                    <input type="submit" value="Log On" />
                </div>

                <div class="editor-label">
                    <%: Html.ActionLink("Register here", "Register", "Account")%> 
                    <%: Html.CheckBoxFor(m => m.RememberMe, new { @class = "pad-left" })%>
                    <%: Html.LabelFor(m => m.RememberMe) %>
                </div>
        </div>
    <% } %>
<%
    }
%>

Затем на HomeController я добавляю процедуру как:

 [HttpPost]
 public ActionResult Index(LogOnModel model, string returnUrl)
 {
     if (ModelState.IsValid)
     {
          // ==>> Check Login against your DB

          // Now check if param returnUrl is empty
          if (!String.IsNullOrEmpty(returnUrl))
              return Redirect(returnUrl);

          return RedirectToAction("Index", "Home");
     }

     // If we got this far, something failed, redisplay form
     return View(model);
 }

Я проверил это с домашней страницы ... это работает !!!

НО, когда я перехожу к представлению «Register» (помните, что «LogonUserControl.ascx» находится внутри «MasterPage», поэтому виден из представления «Register»).

Поэтому, когда я нажимаю кнопку «Регистрация», я получаю сообщение об ошибке: Элемент модели, передаваемый в словарь, имеет тип Site.Models.RegisterModel ', но для этого словаря требуется элемент модели типа Site.Models.LogOnModel'.

ВОПРОС: Означает ли это, что я никогда не смогу объединить части в одно представление?

Допустим, я хочу написать сайт электронной коммерции, и на главной странице я хочу видеть «Самые используемые теги», «Самые покупаемые продукты», «Продукт месяца», «Список категорий»… все в одном и том же просматривать и каждый со своим собственным действием HTTP POST.

Если это возможно с использованием MVC?

1 Ответ

0 голосов
/ 25 октября 2010

Если я правильно понимаю проблему, у вас есть два представления, которые используют один и тот же MasterPage, но которые строго типизированы для разных моделей представления.Главная страница может включать в себя частичное представление, которое также строго типизировано, если его ожидаемая модель представления такая же, как и в родительском представлении.Однако, если вы используете представление с другим типом ViewModel, оно не знает, что делать.

Примите во внимание следующее:

<% Html.RenderPartial("LogOn") %>

Приведенный выше код неявно включает модельданные для текущего отображаемого представления.Это точно так же, как если бы вы сказали:

<% Html.RenderPartial("LogOn", Model) %>

Так что это будет работать, только если Model - это LogOnModel.Помните, что MasterPage на самом деле является частью того, что View наследует, поэтому даже если вы помещаете это в MasterPage, это как если бы вы помещали один и тот же код в каждое представление, которое его наследует.Поэтому, если модель вашего вида не совпадает с моделью PartialView, это не сработает.Один из вариантов - использовать наследование, чтобы каждый ViewModel включал всю информацию, требуемую главной страницей.Этот подход подробно описан здесь .

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

Так что теперь вы можете включить в свою MasterPage любые небольшие частичные представления, которые вы хотите, но вы отделите логику для построения ViewModel каждого изэти виды в отдельное действие контроллера, отвечающее за этот частичный вид:

<% Html.RenderAction("LogOnBox") %>

действие:

public ActionResult LogOnBox()
{
    LogOnModel model = GetLogOnModel();
    return PartialView("LogOnUserControl", model);
}

Теперь, независимо от того, какую модель использует ваше текущее представление, ваша мастер-страницамогут включать «Наиболее используемые теги», «Самые покупаемые продукты», «Продукт месяца», «Список категорий» и т. д. Более того, эти части страницы могут использовать кэширование вывода, поэтому их не нужно восстанавливать.с каждой загрузкой страницы, если они меняются не очень часто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...