Представления в ASP.NET Core MVC

Авторы: Стив Смит (Steve Smith) и Дейв Брок (Dave Brock)

В этом документе описываются представления, используемые в приложениях ASP.NET Core MVC. Сведения о страницах см. в разделе "Общие Razor сведения о Razor страницах" в ASP.NET Core.

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

В ASP.NET Core MVC представления — это .cshtml файлы, использующие язык программирования C#в Razor разметке. Как правило, файлы представлений объединяются в папки с именами, соответствующими отдельным контроллерам приложения. Папки хранятся в Views папке в корне приложения:

Views folder in Solution Explorer of Visual Studio is open with the Home folder open to show About.cshtml, Contact.cshtml, and Index.cshtml files

Контроллер Home представлен папкой Home внутри Views папки. Папка Home содержит представления для Aboutвеб-страниц , Contactа Index также (домашней страницы). Когда пользователь запрашивает одну из этих трех веб-страниц, действия контроллера в Home контроллере определяют, какие из трех представлений используются для сборки и возврата веб-страницы пользователю.

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

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

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

Преимущества использования представлений

Представления помогают реализовать разделение задач в приложении MVC, изолируя разметку пользовательского интерфейса от других частей приложения. Соблюдение принципа SoC делает приложение модульным, что дает несколько преимуществ.

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

Создание представления

Представления, относящиеся к контроллеру, создаются в папке Views/[ControllerName] . Представления, общие между контроллерами, помещаются в папку Views/Shared . Чтобы создать представление, добавьте новый файл и присвойте ему то же имя, что и связанное действие контроллера с расширением .cshtml файла. Чтобы создать представление, соответствующее About действию в контроллере Home , создайте About.cshtml файл в папке Views/Home :

@{
    ViewData["Title"] = "About";
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>Use this area to provide additional information.</p>

Razor Разметка начинается с символа @ . Запустите инструкции C# путем размещения кода C# в Razor блоках кода, заданных фигурными скобками ({ ... }). Примером может служить приведенный выше оператор присвоения значения "About" свойству ViewData["Title"]. Для отображения значений в коде HTML можно просто ссылаться на них с помощью символа @. См. содержимое элементов <h2> и <h3> выше.

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

Указание представлений в контроллерах

Представления обычно возвращаются из действий в качестве ViewResultтипа ActionResult. Метод действия может создавать и возвращать объект ViewResult напрямую, однако обычно так не делается. Так как большинство контроллеров наследуются, Controllerвы просто используете вспомогательный View метод для возврата ViewResult:

HomeController.cs:

public IActionResult About()
{
    ViewData["Message"] = "Your application description page.";

    return View();
}

Когда это действие возвращается, представление, показанное в последнем разделе, About.cshtml отображается как следующая веб-страница:

About page rendered in the Edge browser

Вспомогательный метод View имеет несколько перегрузок. Вы можете дополнительно указать:

  • Представление, которое нужно вернуть, явным образом:

    return View("Orders");
    
  • Модель, которую нужно передать в представление:

    return View(Orders);
    
  • Представление и модель:

    return View("Orders", Orders);
    

Обнаружение представления

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

Метод View (return View();) по умолчанию возвращает представление с тем же именем, что и у метода действия, из которого он был вызван. Например, AboutActionResult имя метода контроллера используется для поиска файла представления с именем About.cshtml. Во-первых, среда выполнения будет выглядеть в папке Views/[ControllerName] представления. Если он не находит соответствующее представление там, он ищет папку Shared для представления.

Не имеет значения, возвращается ли объект ViewResult неявно с помощью метода return View(); или имя представления явно передается в метод View с помощью return View("<ViewName>");. В обоих случаях обнаружение подходящего файла представления происходит в следующем порядке:

  1. Views/\[ControllerName]/\[ViewName].cshtml
  2. Views/Shared/\[ViewName].cshtml

Вместо имени файла можно предоставить путь к файлу представления. Если используется абсолютный путь, начиная с корневого каталога приложения (необязательно начиная с "/" или "~/"), .cshtml необходимо указать расширение:

return View("Views/Home/About.cshtml");

Можно также использовать относительный путь для указания представлений в разных каталогах без .cshtml расширения. HomeControllerВнутри можно вернуть Index представление представлений Manage с относительным путем:

return View("../Manage/Index");

Аналогичным образом, можно указать каталог текущего контроллера с помощью префикса "./":

return View("./About");

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

Вы можете настроить соглашение по умолчанию для того, как представления находятся в приложении с помощью пользовательского IViewLocationExpander.

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

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

Передача данных в представления

Существует несколько подходов к передаче данных в представления:

  • Строго типизированные данные: viewmodel
  • Слабо типизированные данные
    • ViewData (ViewDataAttribute)
    • ViewBag

Строго типизированные данные (viewmodel)

Наиболее надежный подход — указание типа модели в представлении. Такая модель называется viewmodel. Экземпляр типа viewmodel передается в представление из действия.

Использование viewmodel для передачи данных в представление позволяет ему применять строгую проверку типов. Термин строгая типизация (или строго типизированный) означает, что каждая переменная и константа имеет явным образом определенный тип (например, string, int или DateTime). Допустимость типов, используемых в представлении, проверяется во время компиляции.

В Visual Studio и Visual Studio Code строго типизированные члены классов перечисляются с помощью функции IntelliSense. Чтобы просмотреть свойства viewmodel, введите имя переменной viewmodel с точкой (.) после него. Это позволяет писать код быстрее, допуская меньше ошибок.

Укажите модель с помощью директивы @model. Используйте модель с @Model:

@model WebApplication1.ViewModels.Address

<h2>Contact</h2>
<address>
    @Model.Street<br>
    @Model.City, @Model.State @Model.PostalCode<br>
    <abbr title="Phone">P:</abbr> 425.555.0100
</address>

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

public IActionResult Contact()
{
    ViewData["Message"] = "Your contact page.";

    var viewModel = new Address()
    {
        Name = "Microsoft",
        Street = "One Microsoft Way",
        City = "Redmond",
        State = "WA",
        PostalCode = "98052-6399"
    };

    return View(viewModel);
}

В отношении типов моделей, которые можно предоставлять для представления, ограничений нет. Мы рекомендуем использовать модели представлений POCO, которые позволяют определять минимум методов или не определять их вовсе. Как правило, классы viewmodel хранятся в Models папке или отдельной ViewModels папке в корне приложения. Модель представления, используемая Address в приведенном выше примере, представляет собой модель представления POCO, хранящуюся в файле с именем Address.cs:

namespace WebApplication1.ViewModels
{
    public class Address
    {
        public string Name { get; set; }
        public string Street { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string PostalCode { get; set; }
    }
}

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

Слабо типизированные данные (ViewData, [ViewData] атрибуты и ViewBag)

ViewBagпо умолчанию недоступен для использования в Razor классах PagesPageModel.

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

Передача данных между... Пример
Контроллером и представлением Заполнение раскрывающегося списка данными.
Представлением и представлением макета Задание содержимого <title> элемента в представлении макета из файла представления.
Частичным представлением и представлением Мини-приложение, в котором данные выводятся на основе запрошенной пользователем веб-страницы.

На эту коллекцию можно ссылаться в контроллерах и представлениях посредством свойства ViewData или ViewBag. Свойство ViewData представляет собой словарь нестрого типизированных объектов. Свойство ViewBag представляет собой оболочку для свойства ViewData, которая предоставляет динамические свойства для базовой коллекции ViewData. Примечание. Поиск ключей не учитывает регистр для обоих ViewData и ViewBag.

Свойства ViewData и ViewBag разрешаются динамически во время выполнения. Так как они не обеспечивают проверку во время компиляции, их использование обычно приводит к большему числу ошибок, чем использование viewmodel. По этой причине некоторые разработчики предпочитают как можно реже использовать свойства ViewData и ViewBag или не использовать их вовсе.

ViewData

ViewData — это объект, ViewDataDictionary к который осуществляется доступ с помощью string ключей. Строковые данные можно сохранять и использовать напрямую без приведения, однако при извлечении других значений объекта ViewData их необходимо приводить к соответствующим типам. С помощью свойства ViewData можно передавать данные, включая частичные представления и макеты, из контроллеров в представления и внутри представлений.

Ниже приведен пример, в котором с помощью свойства ViewData в действии задаются значения для приветствия и адреса.

public IActionResult SomeAction()
{
    ViewData["Greeting"] = "Hello";
    ViewData["Address"]  = new Address()
    {
        Name = "Steve",
        Street = "123 Main St",
        City = "Hudson",
        State = "OH",
        PostalCode = "44236"
    };

    return View();
}

Работа с данными в представлении:

@{
    // Since Address isn't a string, it requires a cast.
    var address = ViewData["Address"] as Address;
}

@ViewData["Greeting"] World!

<address>
    @address.Name<br>
    @address.Street<br>
    @address.City, @address.State @address.PostalCode
</address>

Атрибут [ViewData]

Другой подход, который используется ViewDataDictionary , — это ViewDataAttribute. Свойства контроллеров или Razor моделей страниц, помеченных атрибутом, [ViewData] хранятся и загружаются из словаря.

В следующем примере контроллер содержит Title свойство, Home помеченное как [ViewData]. Метод About задает заголовок для представления About:

public class HomeController : Controller
{
    [ViewData]
    public string Title { get; set; }

    public IActionResult About()
    {
        Title = "About Us";
        ViewData["Message"] = "Your application description page.";

        return View();
    }
}

В макете заголовок считывается из словаря ViewData.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"] - WebApplication</title>
    ...

ViewBag

ViewBagпо умолчанию недоступен для использования в Razor классах PagesPageModel.

ViewBag — это объект, предоставляющий динамический Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.DynamicViewData доступ к объектам, хранящимся в ViewData. Работать со свойством ViewBag может быть удобнее, так как оно не требует приведения. В приведенном ниже примере демонстрируется использование свойства ViewBag с тем же результатом, что и свойства ViewData ранее.

public IActionResult SomeAction()
{
    ViewBag.Greeting = "Hello";
    ViewBag.Address  = new Address()
    {
        Name = "Steve",
        Street = "123 Main St",
        City = "Hudson",
        State = "OH",
        PostalCode = "44236"
    };

    return View();
}
@ViewBag.Greeting World!

<address>
    @ViewBag.Address.Name<br>
    @ViewBag.Address.Street<br>
    @ViewBag.Address.City, @ViewBag.Address.State @ViewBag.Address.PostalCode
</address>

Использование ViewData и ViewBag одновременно

ViewBagпо умолчанию недоступен для использования в Razor классах PagesPageModel.

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

Задайте заголовок с помощью ViewBag и описание, используя ViewData в верхней части About.cshtml представления:

@{
    Layout = "/Views/Shared/_Layout.cshtml";
    ViewBag.Title = "About Contoso";
    ViewData["Description"] = "Let us tell you about Contoso's philosophy and mission.";
}

В этом примере свойства считываются, причем очередность использования свойств ViewData и ViewBag обратная. _Layout.cshtml В файле получите название с помощью ViewData и получите описание с помощьюViewBag:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"]</title>
    <meta name="description" content="@ViewBag.Description">
    ...

Помните, что строки не требуют приведения значения ViewData. @ViewData["Title"] можно использовать без приведения.

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

<!DOCTYPE html>
<html lang="en">
<head>
    <title>About Contoso</title>
    <meta name="description" content="Let us tell you about Contoso's philosophy and mission.">
    ...

Сводка различий между ViewData и ViewBag

ViewBagпо умолчанию недоступен для использования в Razor классах PagesPageModel.

  • ViewData
    • Производный от ViewDataDictionary, поэтому он имеет свойства словаря, которые могут быть полезны, например ContainsKey, Add, Removeи Clear.
    • Ключи в словаре представляют собой строки, поэтому пробел допустим. Пример: ViewData["Some Key With Whitespace"]
    • Любой тип, кроме string, должен быть приведен в представлении так, чтобы он мог использоваться в ViewData.
  • ViewBag
    • Производный от Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.DynamicViewData, поэтому он позволяет создавать динамические свойства с помощью нотации точек (@ViewBag.SomeKey = <value or object>), и приведение не требуется. Синтаксис свойства ViewBag позволяет быстрее добавлять его в контроллеры и представления.
    • Проще проверять значение NULL. Пример: @ViewBag.Person?.Name

Когда следует использовать ViewData или ViewBag

Свойства ViewData и ViewBag в равной степени подходят для передачи небольших объемов данных между контроллерами и представлениями. Выбор одного из них зависит от предпочтений. Вы можете сочетать объекты ViewData и ViewBag, однако код будет проще для восприятия и обслуживания при последовательном применении одного подхода. Оба свойства разрешаются динамически во время выполнения и поэтому могут приводить к ошибкам во время выполнения. Некоторые команды разработчиков избегают их использования.

Динамические представления

Представления, в которых тип модели не объявляется с помощью @model, но в которые вместо этого передается экземпляр модели (например, return View(Address);), могут ссылаться на свойства экземпляра динамически.

<address>
    @Model.Street<br>
    @Model.City, @Model.State @Model.PostalCode<br>
    <abbr title="Phone">P:</abbr> 425.555.0100
</address>

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

Дополнительные возможности представлений

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

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

Как и многие другие аспекты ASP.NET Core, представления поддерживают внедрение зависимостей, которое позволяет внедрять службы в представления.

Изоляция CSS

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

  • Зависимости от глобальных стилей, которые могут быть сложными в обслуживании.
  • Конфликты стилей во вложенном содержимом.

Чтобы добавить CSS-файл с заданной областью для страницы или представления, поместите стили CSS в сопутствующий файл .cshtml.css, имя которого соответствует имени файла .cshtml. В следующем примере файл Index.cshtml.css предоставляет стили CSS, которые применяются только к представлению или странице Index.cshtml.

Pages/Index.cshtml.css (Razor Pages) или Views/Index.cshtml.css (MVC):

h1 {
    color: red;
}

Изоляция CSS выполняется во время сборки. Платформа повторно создает селекторы CSS в соответствии с разметкой, отображаемой на страницах или в представлениях приложения. Созданные повторно стили CSS объединяются и создаются как статический ресурс {APP ASSEMBLY}.styles.css. Заполнитель {APP ASSEMBLY} — это имя сборки проекта. Ссылка на объединенные стили CSS помещается в макет приложения.

В содержимом <head> файла Pages/Shared/_Layout.cshtml приложения (Razor Pages) или Views/Shared/_Layout.cshtml (MVC) приложения добавьте ссылку на объединенные стили CSS или подтвердите ее наличие:

<link rel="stylesheet" href="~/{APP ASSEMBLY}.styles.css" />

В следующем примере имя сборки приложения — WebApp:

<link rel="stylesheet" href="WebApp.styles.css" />

Стили, определенные в файле CSS с заданной областью, применяются только к отображаемым выходным данным соответствующего файла. В предыдущем примере все объявления CSS h1, определенные в других областях приложения, не будут конфликтовать со стилем заголовка Index. Правила каскадов и наследования стилей CSS и дальше действуют для файлов CSS с заданной областью. Например, стили, примененные непосредственно к элементу <h1> в файле Index.cshtml, переопределяют стили файла CSS с заданной областью в Index.cshtml.css.

Примечание.

Чтобы обеспечить изоляцию стиля CSS при выполнении объединения, импорт CSS в блоки кода Razor не поддерживается.

Изоляция CSS применяется только к элементам HTML. Изоляция CSS не поддерживается для вспомогательных функций тегов.

В объединенном файле CSS каждая страница, представление или компонент Razor связаны с идентификатором области в формате b-{STRING}, где заполнитель {STRING} представляет собой строку из десяти символов, сгенерированную платформой. В следующем примере представлен стиль для предыдущего элемента <h1> на странице Index приложения Razor Pages:

/* /Pages/Index.cshtml.rz.scp.css */
h1[b-3xxtam6d07] {
    color: red;
}

На странице Index, где применяется стиль CSS из объединенного файла, идентификатор области добавляется как атрибут HTML:

<h1 b-3xxtam6d07>

Идентификатор является уникальным для приложения. Во время сборки создается пакет проектов с использованием соглашения {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css, где заполнитель {STATIC WEB ASSETS BASE PATH} является базовым путем к статическим веб-ресурсам.

Если используются другие проекты, такие как пакеты NuGet или библиотеки классов Razor, то объединенный файл:

  • ссылается на стили с помощью импорта CSS;
  • не публикуется как статический веб-ресурс приложения, использующего стили.

Поддержка препроцессоров CSS

Препроцессоры CSS полезны для улучшения разработки CSS с помощью таких функций, как переменные, вложенность, модули, примеси и наследование. Хотя изоляция CSS изначально не поддерживает препроцессоры CSS, такие как Sass и Less, интеграция препроцессоров CSS происходит без проблем, так как компиляция препроцессора выполняется до того, как платформа перезаписывает селекторы CSS в процессе сборки. С помощью Visual Studio, например, настройте существующую компиляцию препроцессора в качестве задачи перед сборкой в диспетчере выполнения задач Visual Studio.

Многие сторонние пакеты NuGet, такие как AspNetCore.SassCompiler, могут компилировать файлы SASS и SCSS в начале процесса сборки перед выполнением изоляции CSS, и дополнительная настройка не требуется.

Конфигурация изоляции CSS

Изоляция CSS позволяет настраивать некоторые сложные сценарии, например включающих зависимости от существующих инструментов или рабочих процессов.

Настройка формата идентификатора области

В этом разделе заполнитель {Pages|Views} — либо Pages для приложений Razor Pages, либо Views для приложений MVC.

По умолчанию идентификаторы областей используют формат b-{STRING}, где заполнитель {STRING} — это строка из десяти символов, сгенерированная платформой. Чтобы настроить формат идентификатора области, измените шаблон в файле проекта:

<ItemGroup>
  <None Update="{Pages|Views}/Index.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

В предыдущем примере CSS, сформированный для Index.cshtml.css, изменяет свой идентификатор области с b-{STRING} на custom-scope-identifier.

Используйте идентификаторы областей, чтобы обеспечить наследование файлов CSS с назначенной областью. В следующем примере файла проекта файл BaseView.cshtml.css содержит общие стили для представлений. Файл DerivedView.cshtml.css наследует эти стили.

<ItemGroup>
  <None Update="{Pages|Views}/BaseView.cshtml.css" CssScope="custom-scope-identifier" />
  <None Update="{Pages|Views}/DerivedView.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Используйте оператор подстановочного знака (*), чтобы предоставить идентификаторы областей для нескольких файлов:

<ItemGroup>
  <None Update="{Pages|Views}/*.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Изменение базового пути для статических веб-ресурсов

Файл CSS с заданной областью создается в корне приложения. Чтобы изменить путь по умолчанию, используйте свойство StaticWebAssetBasePath в файле проекта. В следующем примере файл CSS с заданной областью и остальные ресурсы приложения размещаются по пути _content:

<PropertyGroup>
  <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>

Отключение автоматического объединения

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

<PropertyGroup>
  <DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>

Поддержка библиотеки классов Razor (RCL)

Когда библиотека классов Razor (RCL) предоставляет изолированные стили, атрибут href тега <link> указывает на {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css со следующими заполнителями:

  • {STATIC WEB ASSET BASE PATH}: базовый путь статического веб-ресурса.
  • {PACKAGE ID}: идентификатор пакета библиотеки. Если идентификатор пакета не указан в файле проекта, идентификатору пакета по умолчанию присваивается имя сборки проекта.

В следующем примере :

  • Базовый путь к статическому веб-ресурсу — _content/ClassLib.
  • Имя сборки библиотеки классов — ClassLib.

Pages/Shared/_Layout.cshtml (Razor Pages) или Views/Shared/_Layout.cshtml (MVC):

<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">

Дополнительные сведения о RCL см. в следующих статьях:

Сведения об изоляции CSS в Blazor см. в статье Изоляция CSS Blazor в ASP.NET Core.