Поделиться через


Использование контроллеров и представлений для реализации пользовательского интерфейса списка и сведений

от Майкрософт

Загрузить PDF-файл

Это шаг 4 бесплатного руководства по приложению "NerdDinner" , в которых показано, как создать небольшое, но полное веб-приложение с помощью ASP.NET MVC 1.

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

Если вы используете ASP.NET MVC 3, рекомендуется следовать руководствам по начало работы С MVC 3 или MVC Music Store.

NerdDinner, шаг 4. Контроллеры и представления

При использовании традиционных веб-платформ (классические ASP, PHP, ASP.NET Web Forms и т. д.) входящие URL-адреса обычно сопоставляются с файлами на диске. Например, запрос на URL-адрес, например "/Products.aspx" или "/Products.php", может быть обработан файлом "Products.aspx" или "Products.php".

Веб-платформы MVC сопоставляют URL-адреса с серверным кодом немного иначе. Вместо сопоставления входящих URL-адресов с файлами они сопоставляют URL-адреса с методами классов. Эти классы называются контроллерами и отвечают за обработку входящих HTTP-запросов, обработку входных данных пользователем, получение и сохранение данных, а также определение ответа для отправки клиенту (отображение HTML, скачивание файла, перенаправление на другой URL-адрес и т. д.).

Теперь, когда мы создали базовую модель для нашего приложения NerdDinner, следующим шагом будет добавление контроллера в приложение, которое использует его, чтобы предоставить пользователям возможность навигации по списку данных и подробным сведениям для Dinners на нашем сайте.

Добавление контроллера DinnersController

Начнем с щелчка правой кнопкой мыши по папке Controllers в веб-проекте, а затем выберите команду меню Add-Controller> (вы также можете выполнить эту команду, нажав клавиши CTRL+M, CTRL+C):

Снимок экрана: окно Обозреватель решений с папкой

Откроется диалоговое окно "Добавление контроллера":

Снимок экрана: диалоговое окно

Мы назовем новый контроллер "DinnersController" и нажмите кнопку "Добавить". Visual Studio добавит файл DinnersController.cs в каталог \Controllers:

Снимок экрана: окно Обозреватель решений с выделенным синим цветом файлОм

Он также откроет новый класс DinnersController в редакторе кода.

Добавление методов действий Index() и Details() в класс DinnersController

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

URL-адрес Назначение
/Ужины/ Отображение HTML-списка предстоящих ужинов
/Dinners/Details/[id] Отображение сведений об определенном ужине, обозначенном параметром id, внедренным в URL-адрес, который будет соответствовать DinnerID ужина в базе данных. Например: /Dinners/Details/2 отображает HTML-страницу со сведениями о ужине, значение DinnerID которого равно 2.

Мы опубликуем начальные реализации этих URL-адресов, добавив два открытых метода действий в класс DinnersController, как показано ниже:

public class DinnersController : Controller {

    //
    // HTTP-GET: /Dinners/

    public void Index() {
        Response.Write("<h1>Coming Soon: Dinners</h1>");
    }

    //
    // HTTP-GET: /Dinners/Details/2

    public void Details(int id) {
        Response.Write("<h1>Details DinnerID: " + id + "</h1>");
    }
}

Затем мы запустим приложение NerdDinner и воспользуемся браузером для их вызова. При вводе URL-адреса "/Dinners/" метод Index() будет запущен и будет отправлен следующий ответ:

Снимок экрана: окно ответа, созданное при запуске приложения NerdDinner, с текстом

При вводе URL-адреса "/Dinners/Details/2" метод Details() будет запущен и отправлен следующий ответ:

Снимок экрана: окно ответа, созданное при запуске приложения NerdDinner, с текстом Details Dinner ID: 2.

Возможно, вас интересует, как ASP.NET MVC узнал, чтобы создать класс DinnersController и вызвать эти методы? Чтобы понять это, давайте кратко рассмотрим, как работает маршрутизация.

Основные сведения о маршрутизации MVC ASP.NET

ASP.NET MVC включает мощный механизм маршрутизации URL-адресов, который обеспечивает большую гибкость при управлении сопоставлением URL-адресов с классами контроллера. Это позволяет нам полностью настроить, как ASP.NET MVC выбирает класс контроллера для создания, какой метод вызывается в нем, а также настроить различные способы автоматического анализа переменных из URL-адреса или строки запроса и их отправки в метод в качестве аргументов параметров. Он обеспечивает гибкость для полной оптимизации сайта для SEO (оптимизация поисковой системы), а также публикации любой структуры URL-адреса, которую мы хотим от приложения.

По умолчанию новые ASP.NET проекты MVC поставляются с предварительно настроенным набором правил маршрутизации URL-адресов, которые уже зарегистрированы. Это позволяет нам легко приступить к работе с приложением без необходимости явно настраивать что-либо. Регистрации правил маршрутизации по умолчанию можно найти в классе Application наших проектов, который можно открыть, дважды щелкнув файл Global.asax в корне проекта:

Снимок экрана: окно Обозреватель решений, в котором выделен синим цветом и обведен красным кругом глобальный файл a s a x.

Правила маршрутизации MVC по умолчанию ASP.NET регистрируются в методе RegisterRoutes этого класса:

public void RegisterRoutes(RouteCollection routes) {

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                       // Route name
        "{controller}/{action}/{id}",                    // URL w/ params
        new { controller="Home", action="Index",id="" }  // Param defaults
    );
}

Маршруты. Приведенный выше вызов метода MapRoute()" регистрирует правило маршрутизации по умолчанию, которое сопоставляет входящие URL-адреса с классами контроллеров в формате URL-адреса: "/{контроллер}/{ид}", где "controller" — это имя класса контроллера для создания экземпляра, "action" — это имя открытого метода для его вызова, а "id" — необязательный параметр, внедренный в URL-адрес, который может быть передан в качестве аргумента методу. Третий параметр, передаваемый вызову метода MapRoute(), представляет собой набор значений по умолчанию, используемых для значений контроллера/действия/идентификатора в случае, если они отсутствуют в URL-адресе (Controller = "Home", Action="Index", Id=").

Ниже приведена таблица, демонстрирующая сопоставление различных URL-адресов с помощью правила маршрута по умолчанию /{controllers}/{action}/{id}:

URL-адрес Класс контроллера Метод действия Переданные параметры
/Dinners/Details/2 DinnersController Details(id) id=2
/Dinners/Edit/5 DinnersController Edit(id) id=5
/Dinners/Create DinnersController Create() Н/Д
/Ужины DinnersController Index() Н/Д
/Дома HomeController Index() Н/Д
/ HomeController Index() Н/Д

В последних трех строках отображаются используемые значения по умолчанию (Controller = Home, Action = Index, Id = ""). Так как метод Index регистрируется как имя действия по умолчанию, если оно не указано, URL-адреса "/Dinners" и "/Home" вызывают метод действия Index() в классах Controller. Так как контроллер Home регистрируется как контроллер по умолчанию, если он не указан, URL-адрес "/" приводит к созданию HomeController и вызову метода действия Index().

Если вам не нравятся эти правила маршрутизации URL-адресов по умолчанию, хорошей новостью является то, что их легко изменить — просто измените их в методе RegisterRoutes выше. Однако для приложения NerdDinner мы не будем изменять правила маршрутизации URL-адресов по умолчанию. Вместо этого мы будем использовать их как есть.

Использование DinnerRepository из нашего DinnersController

Теперь заменим текущую реализацию методов действий Index() и Details() DinnersController реализациями, которые используют нашу модель.

Для реализации поведения мы будем использовать класс DinnerRepository, созданный ранее. Начнем с добавления оператора using, который ссылается на пространство имен NerdDinner.Models, а затем объявим экземпляр DinnerRepository как поле в классе DinnerController.

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

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

namespace NerdDinner.Controllers {

    public class DinnersController : Controller {

        DinnerRepository dinnerRepository = new DinnerRepository();

        //
        // GET: /Dinners/

        public void Index() {
            var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        }

        //
        // GET: /Dinners/Details/2

        public void Details(int id) {
            Dinner dinner = dinnerRepository.GetDinner(id);
        }
    }
}

Теперь мы готовы создать HTML-ответ обратно с помощью полученных объектов модели данных.

Использование представлений с нашим контроллером

Хотя можно написать код в наших методах действий для сборки HTML, а затем использовать вспомогательный метод Response.Write() для его отправки клиенту, этот подход быстро становится довольно громоздким. Гораздо лучший подход заключается в выполнении только логики приложений и данных в наших методах действий DinnersController, а затем передавать данные, необходимые для отрисовки HTML-ответа в отдельный шаблон представления, который отвечает за вывод его HTML-представления. Как мы увидим через некоторое время, шаблон представления — это текстовый файл, который обычно содержит сочетание HTML-разметки и внедренного кода отрисовки.

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

Мы можем обновить класс DinnersController, чтобы указать, что мы хотим использовать шаблон представления для обратной отправки ответа пользовательского интерфейса HTML, изменив сигнатуры методов двух методов действий с типа возвращаемого значения void на вместо него иметь тип возвращаемого значения ActionResult. Затем можно вызвать вспомогательный метод View() в базовом классе Controller, чтобы вернуть объект ViewResult, как показано ниже:

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View("Index", dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }
}

Сигнатура используемого выше вспомогательного метода View() выглядит следующим образом:

Снимок экрана: вспомогательный метод View с текстовым представлением представления результатов (имя строкового представления, объектная модель).

Первый параметр вспомогательного метода View() — это имя файла шаблона представления, который необходимо использовать для отрисовки HTML-ответа. Второй параметр — это объект модели, содержащий данные, необходимые шаблону представления для отрисовки HTML-ответа.

В нашем методе действия Index() мы вызываем вспомогательный метод View() и указываем, что мы хотим отобразить HTML-список обедов с помощью шаблона представления "Индекс". Мы передаём шаблон представления последовательность объектов Dinner для создания списка из:

//
    // GET: /Dinners/

    public ActionResult Index() {
    
        var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        
        return View("Index", dinners);
    }

В нашем методе действия Details() мы пытаемся получить объект Dinner, используя идентификатор, указанный в URL-адресе. Если найден допустимый ужин, мы вызываем вспомогательный метод View(), указывая, что мы хотим использовать шаблон представления "Сведения" для отрисовки полученного объекта Dinner. Если запрашивается недопустимый ужин, отображается полезное сообщение об ошибке, указывающее, что ужин не существует с помощью шаблона представления NotFound (и перегруженной версии вспомогательного метода View(), который просто принимает имя шаблона:

//
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.FindDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View("Details", dinner);
    }

Теперь реализуем шаблоны представлений NotFound, Details и Index.

Реализация шаблона представления NotFound

Начнем с реализации шаблона представления NotFound, в котором отображается понятное сообщение об ошибке, указывающее, что запрошенный ужин не найден.

Мы создадим новый шаблон представления, разместив текстовый курсор в методе действия контроллера, а затем щелкните правой кнопкой мыши и выберите команду меню "Добавить представление" (мы также можем выполнить эту команду, введя CTRL-M, CTRL-V):

Снимок экрана: проект с элементом контекстного меню Добавить представление, выделенным синим цветом и обведен красным.

Откроется диалоговое окно "Добавить представление", как показано ниже. По умолчанию диалоговое окно предварительно заполняет имя создаваемого представления в соответствии с именем метода действия, в котором находился курсор при запуске диалогового окна (в данном случае —"Сведения"). Так как мы хотим сначала реализовать шаблон NotFound, мы переопределим это имя представления и присвоим ему значение NotFound:

Снимок экрана: окно

При нажатии кнопки "Добавить" Visual Studio создаст для нас новый шаблон представления "NotFound.aspx" в каталоге \Views\Dinners (который также будет создан, если каталог еще не существует):

Снимок экрана: иерархия папок окна Обозреватель решений с выделенным синим цветом файлом

Он также откроет наш новый шаблон представления NotFound.aspx в редакторе кода:

Снимок экрана: окно редактора кода с открытой точкой

Шаблоны представлений по умолчанию имеют две области содержимого, в которые можно добавить содержимое и код. Первый позволяет настроить заголовок HTML-страницы, отправляемой обратно. Второй позволяет настроить "main содержимое" html-страницы, отправляемой обратно.

Чтобы реализовать шаблон представления NotFound, мы добавим некоторые базовые материалы:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner Not Found
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Dinner Not Found</h2>

    <p>Sorry - but the dinner you requested doesn't exist or was deleted.</p>

</asp:Content>

Затем мы можем опробовать его в браузере. Для этого запросить URL-адрес /Dinners/Details/9999 . Это будет ссылаться на ужин, который в настоящее время не существует в базе данных, и приведет к тому, что метод действия DinnersController.Details() отрисовывает наш шаблон представления NotFound:

Снимок экрана: окно

Одна вещь, которую вы заметите на снимке экрана выше, заключается в том, что наш базовый шаблон представления унаследовал кучу HTML, который окружает main содержимое на экране. Это связано с тем, что наш шаблон представления использует шаблон "master страница", который позволяет нам применять согласованный макет во всех представлениях на сайте. Мы подробнее обсудим, как работают master страницы, в следующей части этого руководства.

Реализация шаблона представления "Сведения"

Теперь давайте реализуем шаблон представления "Сведения", который создаст HTML для одной модели Dinner.

Для этого мы поместим текстовый курсор в метод действия Сведения, а затем щелкните правой кнопкой мыши и выберите команду меню "Добавить представление" (или нажмите клавиши CTRL+M, CTRL-V):

Снимок экрана: окно редактора кода, в котором отображается пункт меню с правой кнопкой мыши Добавить точку представления, выделенную красным цветом.

Откроется диалоговое окно "Добавление представления". Мы оставим имя представления по умолчанию ("Сведения"). Мы также установите флажок "Создать строго типизированное представление" в диалоговом окне и выберите (с помощью раскрывающегося списка со списком) имя типа модели, передаваемой из контроллера в представление. Для этого представления мы передаём объект Dinner (полное имя для этого типа : "NerdDinner.Models.Dinner"):

Снимок экрана: окно

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

Формирование шаблонов создаст начальную реализацию шаблона представления сведений на основе передаваемого ему объекта Dinner. Это позволяет нам быстро приступить к реализации шаблона представления.

При нажатии кнопки "Добавить" Visual Studio создаст для нас новый файл шаблона представления Details.aspx в каталоге \Views\Dinners:

Снимок экрана: окно Обозреватель решений с иерархией папок с папкой Dinners, выделенной синим цветом.

Он также откроет наш новый шаблон представления Details.aspx в редакторе кода. Он будет содержать начальную реализацию шаблона представления сведений на основе модели Dinner. Модуль формирования шаблонов использует отражение .NET для просмотра открытых свойств, предоставляемых в переданном классе, и добавляет соответствующее содержимое в зависимости от каждого найденного типа:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Details
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Details</h2>

    <fieldset>
        <legend>Fields</legend>
        <p>
            DinnerID:
            <%=Html.Encode(Model.DinnerID) %>
        </p>
        <p>
            Title:
            <%=Html.Encode(Model.Title) %>
        </p>
        <p>
            EventDate:
            <%= Html.Encode(String.Format("{0:g}", Model.EventDate)) %>
        </p>
        <p>
            Description:
            <%=Html.Encode(Model.Description) %>
        </p>
        <p>
            HostedBy:
            <%=Html.Encode(Model.HostedBy) %>
        </p>
        <p>
            ContactPhone:
            <%=Html.Encode(Model.ContactPhone) %>
        </p>
        <p>
            Address:
            <%=Html.Encode(Model.Address) %>
        </p>
        <p>
            Country:
            <%=Html.Encode(Model.Country) %>
        </p>
        <p>
            Latitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Latitude)) %>
        </p>
        <p>
            Longitude:
            <%= Html.Encode(String.Format("{0:F}",Model.Longitude)) %>
        </p>
    </fieldset>
    
    <p>
        <%=Html.ActionLink("Edit","Edit", new { id=Model.DinnerID }) %>|
        <%=Html.ActionLink("Back to List", "Index") %>
    </p>
    
</asp:Content>

Мы можем запросить URL-адрес "/Dinners/Details/1" , чтобы увидеть, как выглядит эта реализация шаблонов details в браузере. При использовании этого URL-адреса отобразится один из ужинов, которые мы вручную добавили в базу данных при ее создании:

Снимок экрана: окно ответа приложения, в котором отображается / Dinners / Details / 1 U R L, обведенный красным цветом в поле адреса.

Это позволяет быстро приступить к работе и получить начальную реализацию представления Details.aspx. Затем мы можем изменить его, чтобы настроить пользовательский интерфейс в соответствии с нашим удовлетворением.

При более внимательном просмотре шаблона Details.aspx мы увидим, что он содержит статический HTML-код, а также встроенный код отрисовки. <% наггеты> кода % выполняют код при отображении шаблона представления, а <%= %> самородков кода выполняют код, содержащийся в них, а затем отрисовывают результат в выходном потоке шаблона.

Мы можем написать в представлении код, который обращается к объекту модели Dinner, который был передан из нашего контроллера, используя строго типизированное свойство Model. Visual Studio предоставляет полный код intellisense при доступе к этому свойству Model в редакторе:

Снимок экрана: окно редактора кода с раскрывающимся списком с описанием элемента, выделенным синим цветом.

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

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner: <%=Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2><%=Html.Encode(Model.Title) %></h2>
    <p>
        <strong>When:</strong> 
        <%=Model.EventDate.ToShortDateString() %> 

        <strong>@</strong>
        <%=Model.EventDate.ToShortTimeString() %>
    </p>
    <p>
        <strong>Where:</strong> 
        <%=Html.Encode(Model.Address) %>,
        <%=Html.Encode(Model.Country) %>
    </p>
     <p>
        <strong>Description:</strong> 
        <%=Html.Encode(Model.Description) %>
    </p>       
    <p>
        <strong>Organizer:</strong> 
        <%=Html.Encode(Model.HostedBy) %>
        (<%=Html.Encode(Model.ContactPhone) %>)
    </p>
    
    <%= Html.ActionLink("Edit Dinner", "Edit", new { id=Model.DinnerID })%> |
    <%= Html.ActionLink("Delete Dinner","Delete", new { id=Model.DinnerID})%>   
     
</asp:Content>

Когда мы снова перейдем к URL-адресу "/Dinners/Details/1" , он будет отображаться следующим образом:

Снимок экрана: окно ответа приложения с новой стилизацией представления dot NET Futures.

Реализация шаблона представления "Индекс"

Теперь давайте реализуем шаблон представления "Индекс", который создаст список предстоящих ужинов. Для этого мы поместим текстовый курсор в метод действия Индекс, а затем щелкните правой кнопкой мыши и выберите команду меню "Добавить представление" (или нажмите клавиши CTRL-M, CTRL-V).

В диалоговом окне "Добавление представления" мы оставим шаблон представления с именем "Индекс" и установите флажок "Создать строго типизированное представление". На этот раз мы автоматически создадим шаблон представления "Список" и выберите "NerdDinner.Models.Dinner" в качестве типа модели, передаваемого в представление (поскольку мы указали, что мы создаем шаблон "Список", приведет к тому, что диалоговое окно Добавление представления предполагает передачу последовательности объектов Dinner из контроллера в представление):

Снимок экрана: окно

При нажатии кнопки "Добавить" Visual Studio создаст для нас новый файл шаблона представления Index.aspx в каталоге \Views\Dinners. Он будет "шаблон" начальной реализации в нем, который предоставляет HTML-список ужинов, которые мы передаем в представление.

Когда мы запустите приложение и получите доступ к URL-адресу "/Dinners/" , список ужинов будет отображаться следующим образом:

Снимок экрана: окно ответа приложения со списком обедов в макете сетки после обновления

Приведенное выше табличное решение дает нам сетчатую структуру наших данных о ужине, что не совсем то, что нам нужно для нашего потребителя, обращенного к описанию ужина. Мы можем обновить шаблон представления Index.aspx и изменить его, чтобы вывести меньше столбцов данных, и использовать <элемент ul> для отрисовки их вместо таблицы с помощью приведенного ниже кода:

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>                 
                <%=Html.Encode(dinner.Title) %>            
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
    
</asp:Content>

Мы используем ключевое слово var в приведенном выше операторе foreach при цикле каждого ужина в модели. Те, кто не знаком с C# 3.0, могут подумать, что использование "var" означает, что объект dinner является поздно привязанным. Это означает, что компилятор использует вывод типа для строго типизированного свойства "Model" (тип IEnumerable<Dinner>) и компилирует локальную переменную "dinner" в качестве типа Dinner. Это означает, что мы получаем полную intellisense и проверку во время компиляции в блоках кода:

Снимок экрана: окно редактора кода с раскрывающимся меню с элементом списка Адресов, выделенным серым пунктиром.

Когда мы найдем обновление по URL-адресу /Dinners в нашем браузере, обновленное представление теперь выглядит следующим образом:

Снимок экрана: окно ответа приложения со списком предстоящих ужинов после команды обновления.

Это выглядит лучше, но еще не совсем там. Последний шаг — предоставить конечным пользователям возможность щелкнуть отдельные ужины в списке и просмотреть сведения о них. Мы реализуем это, отрисовав элементы гиперссылок HTML, которые ссылались на метод действия Details в нашем DinnersController.

Эти гиперссылки можно создать в представлении индекса одним из двух способов. Во-первых, вручную создайте элементы HTML<>, как показано ниже, где мы внедряем <%> блоков в <> элемент HTML:

Снимок экрана: окно редактора кода с выделенным классом и текстом блока процента, обведенным красным цветом.

Альтернативный подход, который можно использовать, — воспользоваться преимуществами встроенного вспомогательного метода "Html.ActionLink()" в ASP.NET MVC, который поддерживает программное создание HTML-элемента<>, который связывается с другим методом действия в контроллере:

<%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>

Первый параметр вспомогательного метода Html.ActionLink() — это текст ссылки для отображения (в данном случае название ужина), второй параметр — это имя действия Контроллера, на которое требуется создать ссылку (в данном случае метод Details), а третий параметр — набор параметров для отправки в действие (реализован как анонимный тип с именем или значениями свойства). В этом случае мы указываем параметр id для ужина, с которым мы хотим связаться, и поскольку правило маршрутизации URL-адресов по умолчанию в ASP.NET MVC — "{Controller}/{Action}/{id}", вспомогательный метод Html.ActionLink() создаст следующие выходные данные:

<a href="/Dinners/Details/1">.NET Futures</a>

Для нашего представления Index.aspx мы будем использовать вспомогательный метод Html.ActionLink() и каждый ужин будет содержать ссылку на соответствующий URL-адрес сведений:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Upcoming Dinners
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Upcoming Dinners</h2>

    <ul>
        <% foreach (var dinner in Model) { %>
        
            <li>     
                <%=Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>
                on 
                <%=Html.Encode(dinner.EventDate.ToShortDateString())%>
                @
                <%=Html.Encode(dinner.EventDate.ToShortTimeString())%>
            </li>
            
        <% } %>
    </ul>
</asp:Content>

И теперь, когда мы перейдем по URL-адресу /Dinners , наш список ужинов выглядит следующим образом:

Снимок экрана: окно ответа приложения, в котором отображается список предстоящих ужинов с новыми ссылками, соответствующими элементам списка.

Щелкнув любой из ужинов в списке, мы перейдем к подробным сведениям об этом:

Снимок экрана: окно ответа приложения, в котором показан выбранный элемент списка и соответствующие ему сведения, введенные в базу данных.

Именование на основе соглашений и структура каталогов \Views

ASP.NET приложения MVC по умолчанию используют структуру именования каталогов на основе соглашений при разрешении шаблонов представлений. Это позволяет разработчикам избежать необходимости полностью указывать путь к расположению при ссылке на представления из класса Controller. По умолчанию ASP.NET MVC будет искать файл шаблона представления в каталоге *\Views[ControllerName]* под приложением.

Например, мы работали над классом DinnersController, который явно ссылается на три шаблона представлений: Index, Details и NotFound. ASP.NET MVC будет по умолчанию искать эти представления в каталоге \Views\Dinners под корневым каталогом приложения:

Снимок экрана: окно Обозреватель решений с иерархией папок с папкой Dinners, выделенной синим прямоугольником.

Обратите внимание, что в проекте в настоящее время есть три класса контроллеров (DinnersController, HomeController и AccountController — последние два были добавлены по умолчанию при создании проекта), а в каталоге \Views есть три вложенных каталога (по одному для каждого контроллера).

Представления, на которые ссылаются контроллеры "Главная" и "Учетные записи", автоматически разрешают шаблоны представлений из соответствующих каталогов \Views\Home и \Views\Account . Вложенный каталог \Views\Shared предоставляет способ хранения шаблонов представлений, которые повторно используются на нескольких контроллерах в приложении. Когда ASP.NET MVC пытается разрешить шаблон представления, он сначала проверка в каталоге \Views[Controller], и если не удается найти шаблон представления, он будет находиться в каталоге \Views\Shared.

Что касается именования отдельных шаблонов представлений, рекомендуется использовать для шаблона представления то же имя, что и метод действия, который вызвал его отрисовку. Например, выше наш метод действия "Индекс" использует представление "Индекс" для отрисовки результата представления, а метод действия "Сведения" использует представление "Сведения" для отрисовки результатов. Это позволяет быстро узнать, какой шаблон связан с каждым действием.

Разработчикам не нужно явно указывать имя шаблона представления, если имя шаблона представления совпадает с именем метода действия, вызываемого на контроллере. Вместо этого можно просто передать объект модели во вспомогательный метод "View()" (без указания имени представления), и ASP.NET MVC автоматически выдаст вывод, что мы хотим использовать шаблон представления \Views[ControllerName][ActionName] на диске для отрисовки.

Это позволяет нам немного очистить код контроллера и избежать дублирования имени в коде дважды:

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();

        return View(dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View(dinner);
    }
}

Приведенный выше код — это все, что необходимо для реализации хорошего описания и сведений о ужине для сайта.

Следующий шаг

Теперь у нас есть хороший ужин просмотра опыт построен.

Теперь включим поддержку редактирования формы данных CRUD (создание, чтение, обновление, удаление).