Wyświetlanie składników w programie ASP.NET Core

Autor: Rick Anderson

Składniki widoku

Składniki widoku są podobne do widoków częściowych, ale są znacznie bardziej zaawansowane. Składniki widoku nie korzystają z powiązania modelu. Zależą one od danych przekazywanych podczas wywoływania składnika widoku. Ten artykuł został napisany przy użyciu kontrolerów i widoków, ale składniki widoku współpracują ze stronamiRazor.

Składnik widoku:

  • Renderuje fragment, a nie całą odpowiedź.
  • Obejmuje te same kwestie związane z separacją i korzyściami z testowania znalezionymi między kontrolerem a widokiem.
  • Może mieć parametry i logikę biznesową.
  • Jest zwykle wywoływany ze strony układu.

Składniki widoku są przeznaczone w dowolnym miejscu, gdzie logika renderowania wielokrotnego użytku jest zbyt złożona dla widoku częściowego, takiego jak:

  • Menu nawigacji dynamicznej
  • Tagowanie chmury, w której wysyła zapytania do bazy danych
  • Panel logowania
  • Koszyk
  • Ostatnio opublikowane artykuły
  • Zawartość paska bocznego w blogu
  • Panel logowania, który będzie renderowany na każdej stronie i wyświetla linki do wylogowania lub logowania, w zależności od stanu logowania użytkownika

Składnik widoku składa się z dwóch części:

  • Klasa, zazwyczaj pochodzi z ViewComponent
  • Wynik, który zwraca, zazwyczaj jest to widok.

Podobnie jak kontrolery, składnik widoku może być poco, ale większość deweloperów korzysta z metod i właściwości dostępnych przez wyprowadzanie z ViewComponentklasy .

Podczas rozważania, czy wyświetlanie składników spełnia specyfikacje aplikacji, rozważ użycie Razor składników. Razor składniki łączą również znaczniki z kodem C#, aby tworzyć jednostki interfejsu użytkownika wielokrotnego użytku. Razor składniki są zaprojektowane pod kątem produktywności deweloperów podczas zapewniania logiki i kompozycji interfejsu użytkownika po stronie klienta. Aby uzyskać więcej informacji, zobacz ASP.NET Podstawowe Razor składniki. Aby uzyskać informacje na temat dołączania Razor składników do aplikacji MVC lub Razor Pages, zobacz Integrowanie składników ASP.NET Core Razor z aplikacjami platformy ASP.NET Core.

Tworzenie składnika widoku

Ta sekcja zawiera ogólne wymagania dotyczące tworzenia składnika widoku. W dalszej części artykułu szczegółowo sprawdzimy każdy krok i utworzymy składnik widoku.

Klasa składników widoku

Klasę składników widoku można utworzyć za pomocą dowolnego z następujących elementów:

  • Wyprowadzanie z ViewComponent
  • Dekorowanie klasy za pomocą atrybutu [ViewComponent] lub wyprowadzanie z klasy z atrybutem [ViewComponent]
  • Tworzenie klasy, w której nazwa kończy się sufiksem ViewComponent

Podobnie jak kontrolery, składniki widoku muszą być publiczne, niezagnieżdżone i nie abstrakcyjne klasy. Nazwa składnika widoku to nazwa klasy z usuniętym sufiksem ViewComponent . Można go również jawnie określić przy użyciu Name właściwości .

Klasa składników widoku:

  • Obsługuje wstrzykiwanie zależności konstruktora
  • Nie bierze udziału w cyklu życia kontrolera, dlatego filtry nie mogą być używane w składniku widoku

Aby zapobiec traktowaniu klasy, która ma sufiks bez uwzględniania ViewComponent wielkości liter, jest traktowana jako składnik widoku, udekoruj klasę za pomocą atrybutu [NonViewComponent] :

using Microsoft.AspNetCore.Mvc;

[NonViewComponent]
public class ReviewComponent
{
    public string Status(string name) => JobStatus.GetCurrentStatus(name);
}

Wyświetlanie metod składników

Składnik widoku definiuje jego logikę w elemencie :

  • InvokeAsync metoda zwracająca Task<IViewComponentResult>wartość .
  • Invoke metoda synchroniczna zwracająca element IViewComponentResult.

Parametry pochodzą bezpośrednio z wywołania składnika widoku, a nie z powiązania modelu. Składnik widoku nigdy nie obsługuje bezpośrednio żądania. Zazwyczaj składnik widoku inicjuje model i przekazuje go do widoku, wywołując metodę View . Podsumowując, wyświetl metody składników:

  • Zdefiniuj metodę InvokeAsync zwracającą metodę Task<IViewComponentResult> synchroniczną Invoke lub zwracającą IViewComponentResultwartość .
  • Zazwyczaj inicjuje model i przekazuje go do widoku, wywołując metodę ViewComponent.View .
  • Parametry pochodzą z metody wywołującej, a nie z protokołu HTTP. Nie ma powiązania modelu.
  • Nie są dostępne bezpośrednio jako punkt końcowy HTTP. Są one zwykle wywoływane w widoku. Składnik widoku nigdy nie obsługuje żądania.
  • Są przeciążone podpisem, a nie wszelkimi szczegółami z bieżącego żądania HTTP.

Wyświetlanie ścieżki wyszukiwania

Środowisko uruchomieniowe wyszukuje widok w następujących ścieżkach:

  • /Views/{Nazwa kontrolera}/Składniki/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Views/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Pages/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Areas/{Nazwa obszaru}/Widoki/Udostępnione/Składniki/{Wyświetl nazwę składnika}/{Nazwa widoku}

Ścieżka wyszukiwania dotyczy projektów przy użyciu kontrolerów i widoków i Razor stron.

Domyślna nazwa widoku składnika widoku to Default, co oznacza, że pliki widoku będą zwykle mieć nazwę Default.cshtml. Podczas tworzenia wyniku składnika widoku lub wywoływania View metody można określić inną nazwę widoku.

Zalecamy nazewnictwo pliku Default.cshtml widoku i użycie ścieżki Views/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku} . Składnik PriorityList widoku używany w tym przykładzie jest używany Views/Shared/Components/PriorityList/Default.cshtml dla widoku składnika widoku.

Dostosowywanie ścieżki wyszukiwania widoku

Aby dostosować ścieżkę wyszukiwania widoku, zmodyfikuj RazorViewLocationFormats kolekcję . Aby na przykład wyszukać widoki w ścieżce /Components/{View Component Name}/{View Name}, dodaj nowy element do kolekcji:

using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews()
    .AddRazorOptions(options =>
    {
        options.ViewLocationFormats.Add("/{0}.cshtml");
    });

builder.Services.AddDbContext<ToDoContext>(options =>
        options.UseInMemoryDatabase("db"));

var app = builder.Build();

// Remaining code removed for brevity.

W poprzednim kodzie symbol zastępczy {0} reprezentuje ścieżkę Components/{View Component Name}/{View Name}.

Wywoływanie składnika widoku

Aby użyć składnika widoku, wywołaj następujące elementy w widoku:

@await Component.InvokeAsync("Name of view component",
                             {Anonymous Type Containing Parameters})

Parametry są przekazywane do InvokeAsync metody . Składnik PriorityList widoku opracowany w artykule jest wywoływany z Views/ToDo/Index.cshtml pliku widoku. W poniższym kodzie metoda jest wywoływana InvokeAsync z dwoma parametrami:

</table>

<div>
    Maximum Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync("PriorityList",
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Wywoływanie składnika widoku jako pomocnika tagów

Składnik widoku można wywołać jako pomocnik tagów:

<div>
       Maxium Priority: @ViewData["maxPriority"] <br />
       Is Complete:  @ViewData["isDone"]
    @{
        int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
        bool isDone = Convert.ToBoolean(ViewData["isDone"]);
    }
    <vc:priority-list max-priority=maxPriority is-done=isDone>
    </vc:priority-list>
</div>

Parametry klasy i metody Pascal cased dla pomocników tagów są tłumaczone na ich przypadek kebab. Pomocnik tagów do wywoływania składnika widoku używa <vc></vc> elementu . Składnik widoku jest określony w następujący sposób:

<vc:[view-component-name]
  parameter1="parameter1 value"
  parameter2="parameter2 value">
</vc:[view-component-name]>

Aby użyć składnika widoku jako pomocnika tagów, zarejestruj zestaw zawierający składnik widoku przy użyciu @addTagHelper dyrektywy . Jeśli składnik widoku znajduje się w zestawie o nazwie MyWebApp, dodaj następującą dyrektywę _ViewImports.cshtml do pliku:

@addTagHelper *, MyWebApp

Składnik widoku można zarejestrować jako pomocnik tagów do dowolnego pliku, który odwołuje się do składnika widoku. Aby uzyskać więcej informacji na temat rejestrowania pomocników tagów, zobacz Zarządzanie zakresem pomocnika tagów.

Metoda InvokeAsync używana w tym samouczku:

@await Component.InvokeAsync("PriorityList",
                 new { 
                     maxPriority =  ViewData["maxPriority"],
                     isDone = ViewData["isDone"]  }
                 )

W poprzednim znaczniku PriorityList składnik widoku staje się .priority-list Parametry składnika widoku są przekazywane jako atrybuty w przypadku kebab.

Wywoływanie składnika widoku bezpośrednio z kontrolera

Składniki widoku są zwykle wywoływane z widoku, ale mogą być wywoływane bezpośrednio z metody kontrolera. Chociaż składniki widoku nie definiują punktów końcowych, takich jak kontrolery, można zaimplementować akcję kontrolera zwracającą zawartość obiektu ViewComponentResult .

W poniższym przykładzie składnik widoku jest wywoływany bezpośrednio z kontrolera:

public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
    return ViewComponent("PriorityList",
        new { 
           maxPriority = maxPriority,
           isDone = isDone
        });
}

Tworzenie podstawowego składnika widoku

Pobierz, skompiluj i przetestuj kod początkowy. Jest to podstawowy projekt z kontrolerem ToDo , który wyświetla listę elementów zadań do wykonania .

List of ToDos

Aktualizowanie kontrolera w celu przekazania priorytetu i stanu ukończenia

Zaktualizuj metodę tak Index , aby korzystała z parametrów stanu priorytetu i ukończenia:

using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;

namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
    private readonly ToDoContext _ToDoContext;

    public ToDoController(ToDoContext context)
    {
        _ToDoContext = context;
        _ToDoContext.Database.EnsureCreated();
    }

    public IActionResult Index(int maxPriority = 2, bool isDone = false)
    {
        var model = _ToDoContext!.ToDo!.ToList();
        ViewData["maxPriority"] = maxPriority;
        ViewData["isDone"] = isDone;
        return View(model);
    }

Dodawanie klasy ViewComponent

Dodaj klasę ViewComponent do elementu ViewComponents/PriorityListViewComponent.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents;

public class PriorityListViewComponent : ViewComponent
{
    private readonly ToDoContext db;

    public PriorityListViewComponent(ToDoContext context) => db = context;

    public async Task<IViewComponentResult> InvokeAsync(
                                            int maxPriority, bool isDone)
    {
        var items = await GetItemsAsync(maxPriority, isDone);
        return View(items);
    }

    private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
    {
        return db!.ToDo!.Where(x => x.IsDone == isDone &&
                             x.Priority <= maxPriority).ToListAsync();
    }
}

Uwagi dotyczące kodu:

  • Klasy składników widoku mogą być zawarte w dowolnym folderze w projekcie.

  • Ponieważ nazwa klasy PriorityListViewComponent kończy się sufiksem ViewComponent, środowisko uruchomieniowe używa ciągu PriorityList podczas odwoływania się do składnika klasy z widoku.

  • Atrybut [ViewComponent] może zmienić nazwę używaną do odwołowania się do składnika widoku. Na przykład klasa mogła mieć nazwę XYZ z następującym [ViewComponent] atrybutem:

    [ViewComponent(Name = "PriorityList")]
       public class XYZ : ViewComponent
    
  • Atrybut [ViewComponent] w poprzednim kodzie informuje selektora składników widoku do użycia:

    • Nazwa PriorityList podczas wyszukiwania widoków skojarzonych z składnikiem
    • Ciąg "PriorityList" podczas odwoływania się do składnika klasy z widoku.
  • Składnik używa iniekcji zależności, aby udostępnić kontekst danych.

  • InvokeAsync Uwidacznia metodę, którą można wywołać z widoku, i może przyjmować dowolną liczbę argumentów.

  • Metoda InvokeAsync zwraca zestaw ToDo elementów spełniających isDone parametry i maxPriority .

Tworzenie widoku składnika Razor

  • Utwórz folder Views/Shared/Components. Ten folder musi mieć nazwę Components.

  • Utwórz folder Views/Shared/Components/PriorityList. Ta nazwa folderu musi być zgodna z nazwą klasy składnika widoku lub nazwą klasy minus sufiks. ViewComponent Jeśli atrybut jest używany, nazwa klasy musi być zgodna z oznaczeniem atrybutu.

  • Views/Shared/Components/PriorityList/Default.cshtmlRazor Utwórz widok:

    @model IEnumerable<ViewComponentSample.Models.TodoItem>
    
    <h3>Priority Items</h3>
    <ul>
        @foreach (var todo in Model)
        {
            <li>@todo.Name</li>
        }
    </ul>
    

    Widok Razor przyjmuje listę TodoItem i wyświetla je. Jeśli metoda składnika InvokeAsync widoku nie przekazuje nazwy widoku, wartość Domyślna jest używana dla nazwy widoku zgodnie z konwencją. Aby zastąpić domyślny styl określonego kontrolera, dodaj widok do folderu widoku specyficznego dla kontrolera (na przykład Views/ToDo/Components/PriorityList/Default.cshtml)..

    Jeśli składnik widoku jest specyficzny dla kontrolera, można go dodać do folderu specyficznego dla kontrolera. Na przykład Views/ToDo/Components/PriorityList/Default.cshtml jest specyficzny dla kontrolera.

  • div Dodaj element zawierający wywołanie składnika listy priorytetów w dolnej części Views/ToDo/index.cshtml pliku:

    </table>
    
    <div>
        Maximum Priority: @ViewData["maxPriority"] <br />
        Is Complete:  @ViewData["isDone"]
        @await Component.InvokeAsync("PriorityList",
                         new { 
                             maxPriority =  ViewData["maxPriority"],
                             isDone = ViewData["isDone"]  }
                         )
    </div>
    

Znacznik @await Component.InvokeAsync pokazuje składnię wywoływania składników widoku. Pierwszym argumentem jest nazwa składnika, który chcemy wywołać lub wywołać. Kolejne parametry są przekazywane do składnika. InvokeAsync może przyjmować dowolną liczbę argumentów.

Testowanie aplikacji. Na poniższej ilustracji przedstawiono listę Zadań do wykonania i elementy priorytetu:

todo list and priority items

Składnik widoku można wywołać bezpośrednio z kontrolera:

public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
    return ViewComponent("PriorityList",
        new { 
           maxPriority = maxPriority,
           isDone = isDone
        });
}

priority items from IndexVC action

Określanie nazwy składnika widoku

Składnik widoku złożonego może wymagać określenia widoku innego niż domyślny w niektórych warunkach. Poniższy kod pokazuje, jak określić widok "PVC" z InvokeAsync metody . Zaktualizuj metodę InvokeAsyncPriorityListViewComponent w klasie .

public async Task<IViewComponentResult> InvokeAsync(
                                           int maxPriority, bool isDone)
{
    string MyView = "Default";
    // If asking for all completed tasks, render with the "PVC" view.
    if (maxPriority > 3 && isDone == true)
    {
        MyView = "PVC";
    }
    var items = await GetItemsAsync(maxPriority, isDone);
    return View(MyView, items);
}

Views/Shared/Components/PriorityList/Default.cshtml Skopiuj plik do widoku o nazwie Views/Shared/Components/PriorityList/PVC.cshtml. Dodaj nagłówek, aby wskazać, że widok PVC jest używany.

@model IEnumerable<ViewComponentSample.Models.TodoItem>

<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
    @foreach (var todo in Model)
    {
        <li>@todo.Name</li>
    }
</ul>

Uruchom aplikację i sprawdź widok PVC.

Priority View Component

Jeśli widok PVC nie jest renderowany, sprawdź, czy składnik widoku o priorytecie 4 lub wyższym jest wywoływany.

Badanie ścieżki widoku

  • Zmień parametr priorytetu na trzy lub mniej, aby widok priorytetu nie został zwrócony.

  • Tymczasowo zmień nazwę elementu na Views/ToDo/Components/PriorityList/Default.cshtml1Default.cshtml.

  • Przetestuj aplikację, wystąpi następujący błąd:

    An unhandled exception occurred while processing the request.
    InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched:
    /Views/ToDo/Components/PriorityList/Default.cshtml
    /Views/Shared/Components/PriorityList/Default.cshtml
    
  • Skopiuj folder Views/ToDo/Components/PriorityList/1Default.cshtml do folderu Views/Shared/Components/PriorityList/Default.cshtml.

  • Dodaj znaczniki do widoku składników udostępnionego widoku zadań do wykonania, aby wskazać, że widok pochodzi z folderu Udostępnione.

  • Przetestuj widok składników udostępnionych .

ToDo output with Shared component view

Unikaj zakodowanych ciągów

W przypadku bezpieczeństwa czasu kompilacji zastąp nazwę składnika widoku zakodowanego na podstawie kodu nazwą klasy. Zaktualizuj plik PriorityListViewComponent.cs, aby nie używać sufiksu "ViewComponent":

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents;

public class PriorityList : ViewComponent
{
    private readonly ToDoContext db;

    public PriorityList(ToDoContext context)
    {
        db = context;
    }

    public async Task<IViewComponentResult> InvokeAsync(
                                               int maxPriority, bool isDone)
    {
        var items = await GetItemsAsync(maxPriority, isDone);
        return View(items);
    }

    private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
    {
        return db!.ToDo!.Where(x => x.IsDone == isDone &&
                             x.Priority <= maxPriority).ToListAsync();
    }
}

Plik widoku :

</table>

<div>
    Testing nameof(PriorityList) <br />

    Maxium Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync(nameof(PriorityList),
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Przeciążenie Component.InvokeAsync metody, która przyjmuje typ CLR, używa typeof operatora :

</table>

<div>
    Testing typeof(PriorityList) <br />

    Maxium Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync(typeof(PriorityList),
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Wykonywanie pracy synchronicznej

Platforma obsługuje wywoływanie metody synchronicznej, jeśli praca asynchroniczna Invoke nie jest wymagana. Poniższa metoda tworzy synchroniczny Invoke składnik widoku:

using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents
{
    public class PriorityListSync : ViewComponent
    {
        private readonly ToDoContext db;

        public PriorityListSync(ToDoContext context)
        {
            db = context;
        }

        public IViewComponentResult Invoke(int maxPriority, bool isDone)
        {
 
            var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
                                  x.Priority <= maxPriority).ToList();
            return View(x);
        }
    }
}

Plik składnika Razor widoku:

<div>
    Testing nameof(PriorityList) <br />

    Maxium Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync(nameof(PriorityListSync),
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Składnik widoku jest wywoływany w Razor pliku (na przykład Views/Home/Index.cshtml) przy użyciu jednego z następujących metod:

Aby użyć podejścia, wywołaj metodę IViewComponentHelperComponent.InvokeAsync:

@await Component.InvokeAsync(nameof(PriorityList),
                             new { maxPriority = 4, isDone = true })

Aby użyć pomocnika tagów, zarejestruj zestaw zawierający składnik widoku przy użyciu @addTagHelper dyrektywy (składnik widoku znajduje się w zestawie o nazwie MyWebApp):

@addTagHelper *, MyWebApp

Użyj pomocnika tagu składnika widoku w Razor pliku znaczników:

<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>

Sygnatura PriorityList.Invoke metody metody jest synchroniczna, ale Razor znajduje i wywołuje metodę w Component.InvokeAsync pliku znaczników.

Dodatkowe zasoby

Składniki widoku

Składniki widoku są podobne do widoków częściowych, ale są znacznie bardziej zaawansowane. Składniki widoku nie korzystają z powiązania modelu. Zależą one od danych przekazywanych podczas wywoływania składnika widoku. Ten artykuł został napisany przy użyciu kontrolerów i widoków, ale składniki widoku współpracują ze stronamiRazor.

Składnik widoku:

  • Renderuje fragment, a nie całą odpowiedź.
  • Obejmuje te same kwestie związane z separacją i korzyściami z testowania znalezionymi między kontrolerem a widokiem.
  • Może mieć parametry i logikę biznesową.
  • Jest zwykle wywoływany ze strony układu.

Składniki widoku są przeznaczone w dowolnym miejscu, gdzie logika renderowania wielokrotnego użytku jest zbyt złożona dla widoku częściowego, takiego jak:

  • Menu nawigacji dynamicznej
  • Tagowanie chmury, w której wysyła zapytania do bazy danych
  • Panel logowania
  • Koszyk
  • Ostatnio opublikowane artykuły
  • Zawartość paska bocznego w blogu
  • Panel logowania, który będzie renderowany na każdej stronie i wyświetla linki do wylogowania lub logowania, w zależności od stanu logowania użytkownika

Składnik widoku składa się z dwóch części:

  • Klasa, zazwyczaj pochodzi z ViewComponent
  • Wynik, który zwraca, zazwyczaj jest to widok.

Podobnie jak kontrolery, składnik widoku może być poco, ale większość deweloperów korzysta z metod i właściwości dostępnych przez wyprowadzanie z ViewComponentklasy .

Podczas rozważania, czy wyświetlanie składników spełnia specyfikacje aplikacji, rozważ użycie Razor składników. Razor składniki łączą również znaczniki z kodem C#, aby tworzyć jednostki interfejsu użytkownika wielokrotnego użytku. Razor składniki są zaprojektowane pod kątem produktywności deweloperów podczas zapewniania logiki i kompozycji interfejsu użytkownika po stronie klienta. Aby uzyskać więcej informacji, zobacz ASP.NET Podstawowe Razor składniki. Aby uzyskać informacje na temat dołączania Razor składników do aplikacji MVC lub Razor Pages, zobacz Prerender i integrowanie składników ASP.NET CoreRazor.

Tworzenie składnika widoku

Ta sekcja zawiera ogólne wymagania dotyczące tworzenia składnika widoku. W dalszej części artykułu szczegółowo sprawdzimy każdy krok i utworzymy składnik widoku.

Klasa składników widoku

Klasę składników widoku można utworzyć za pomocą dowolnego z następujących elementów:

  • Wyprowadzanie z ViewComponent
  • Dekorowanie klasy za pomocą atrybutu [ViewComponent] lub wyprowadzanie z klasy z atrybutem [ViewComponent]
  • Tworzenie klasy, w której nazwa kończy się sufiksem ViewComponent

Podobnie jak kontrolery, składniki widoku muszą być publiczne, niezagnieżdżone i nie abstrakcyjne klasy. Nazwa składnika widoku to nazwa klasy z usuniętym sufiksem ViewComponent . Można go również jawnie określić przy użyciu Name właściwości .

Klasa składników widoku:

  • Obsługuje wstrzykiwanie zależności konstruktora
  • Nie bierze udziału w cyklu życia kontrolera, dlatego filtry nie mogą być używane w składniku widoku

Aby zapobiec traktowaniu klasy, która ma sufiks bez uwzględniania ViewComponent wielkości liter, jest traktowana jako składnik widoku, udekoruj klasę za pomocą atrybutu [NonViewComponent] :

using Microsoft.AspNetCore.Mvc;

[NonViewComponent]
public class ReviewComponent
{
    public string Status(string name) => JobStatus.GetCurrentStatus(name);
}

Wyświetlanie metod składników

Składnik widoku definiuje jego logikę w elemencie :

  • InvokeAsync metoda zwracająca Task<IViewComponentResult>wartość .
  • Invoke metoda synchroniczna zwracająca element IViewComponentResult.

Parametry pochodzą bezpośrednio z wywołania składnika widoku, a nie z powiązania modelu. Składnik widoku nigdy nie obsługuje bezpośrednio żądania. Zazwyczaj składnik widoku inicjuje model i przekazuje go do widoku, wywołując metodę View . Podsumowując, wyświetl metody składników:

  • Zdefiniuj metodę InvokeAsync zwracającą metodę Task<IViewComponentResult> synchroniczną Invoke lub zwracającą IViewComponentResultwartość .
  • Zazwyczaj inicjuje model i przekazuje go do widoku, wywołując metodę ViewComponent.View .
  • Parametry pochodzą z metody wywołującej, a nie z protokołu HTTP. Nie ma powiązania modelu.
  • Nie są dostępne bezpośrednio jako punkt końcowy HTTP. Są one zwykle wywoływane w widoku. Składnik widoku nigdy nie obsługuje żądania.
  • Są przeciążone podpisem, a nie wszelkimi szczegółami z bieżącego żądania HTTP.

Wyświetlanie ścieżki wyszukiwania

Środowisko uruchomieniowe wyszukuje widok w następujących ścieżkach:

  • /Views/{Nazwa kontrolera}/Składniki/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Views/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Pages/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Areas/{Nazwa obszaru}/Widoki/Udostępnione/Składniki/{Wyświetl nazwę składnika}/{Nazwa widoku}

Ścieżka wyszukiwania dotyczy projektów przy użyciu kontrolerów i widoków i Razor stron.

Domyślna nazwa widoku składnika widoku to Default, co oznacza, że pliki widoku będą zwykle mieć nazwę Default.cshtml. Podczas tworzenia wyniku składnika widoku lub wywoływania View metody można określić inną nazwę widoku.

Zalecamy nazewnictwo pliku Default.cshtml widoku i użycie ścieżki Views/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku} . Składnik PriorityList widoku używany w tym przykładzie jest używany Views/Shared/Components/PriorityList/Default.cshtml dla widoku składnika widoku.

Dostosowywanie ścieżki wyszukiwania widoku

Aby dostosować ścieżkę wyszukiwania widoku, zmodyfikuj RazorViewLocationFormats kolekcję . Aby na przykład wyszukać widoki w ścieżce /Components/{View Component Name}/{View Name}, dodaj nowy element do kolekcji:

using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews()
    .AddRazorOptions(options =>
    {
        options.ViewLocationFormats.Add("/{0}.cshtml");
    });

builder.Services.AddDbContext<ToDoContext>(options =>
        options.UseInMemoryDatabase("db"));

var app = builder.Build();

// Remaining code removed for brevity.

W poprzednim kodzie symbol zastępczy {0} reprezentuje ścieżkę Components/{View Component Name}/{View Name}.

Wywoływanie składnika widoku

Aby użyć składnika widoku, wywołaj następujące elementy w widoku:

@await Component.InvokeAsync("Name of view component",
                             {Anonymous Type Containing Parameters})

Parametry są przekazywane do InvokeAsync metody . Składnik PriorityList widoku opracowany w artykule jest wywoływany z Views/ToDo/Index.cshtml pliku widoku. W poniższym kodzie metoda jest wywoływana InvokeAsync z dwoma parametrami:

</table>

<div>
    Maximum Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync("PriorityList",
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Wywoływanie składnika widoku jako pomocnika tagów

Składnik widoku można wywołać jako pomocnik tagów:

<div>
       Maxium Priority: @ViewData["maxPriority"] <br />
       Is Complete:  @ViewData["isDone"]
    @{
        int maxPriority = Convert.ToInt32(ViewData["maxPriority"]);
        bool isDone = Convert.ToBoolean(ViewData["isDone"]);
    }
    <vc:priority-list max-priority=maxPriority is-done=isDone>
    </vc:priority-list>
</div>

Parametry klasy i metody Pascal cased dla pomocników tagów są tłumaczone na ich przypadek kebab. Pomocnik tagów do wywoływania składnika widoku używa <vc></vc> elementu . Składnik widoku jest określony w następujący sposób:

<vc:[view-component-name]
  parameter1="parameter1 value"
  parameter2="parameter2 value">
</vc:[view-component-name]>

Aby użyć składnika widoku jako pomocnika tagów, zarejestruj zestaw zawierający składnik widoku przy użyciu @addTagHelper dyrektywy . Jeśli składnik widoku znajduje się w zestawie o nazwie MyWebApp, dodaj następującą dyrektywę _ViewImports.cshtml do pliku:

@addTagHelper *, MyWebApp

Składnik widoku można zarejestrować jako pomocnik tagów do dowolnego pliku, który odwołuje się do składnika widoku. Aby uzyskać więcej informacji na temat rejestrowania pomocników tagów, zobacz Zarządzanie zakresem pomocnika tagów.

Metoda InvokeAsync używana w tym samouczku:

@await Component.InvokeAsync("PriorityList",
                 new { 
                     maxPriority =  ViewData["maxPriority"],
                     isDone = ViewData["isDone"]  }
                 )

W poprzednim znaczniku PriorityList składnik widoku staje się .priority-list Parametry składnika widoku są przekazywane jako atrybuty w przypadku kebab.

Wywoływanie składnika widoku bezpośrednio z kontrolera

Składniki widoku są zwykle wywoływane z widoku, ale mogą być wywoływane bezpośrednio z metody kontrolera. Chociaż składniki widoku nie definiują punktów końcowych, takich jak kontrolery, można zaimplementować akcję kontrolera zwracającą zawartość obiektu ViewComponentResult .

W poniższym przykładzie składnik widoku jest wywoływany bezpośrednio z kontrolera:

public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
    return ViewComponent("PriorityList",
        new { 
           maxPriority = maxPriority,
           isDone = isDone
        });
}

Tworzenie podstawowego składnika widoku

Pobierz, skompiluj i przetestuj kod początkowy. Jest to podstawowy projekt z kontrolerem ToDo , który wyświetla listę elementów zadań do wykonania .

List of ToDos

Aktualizowanie kontrolera w celu przekazania priorytetu i stanu ukończenia

Zaktualizuj metodę tak Index , aby korzystała z parametrów stanu priorytetu i ukończenia:

using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;

namespace ViewComponentSample.Controllers;
public class ToDoController : Controller
{
    private readonly ToDoContext _ToDoContext;

    public ToDoController(ToDoContext context)
    {
        _ToDoContext = context;
        _ToDoContext.Database.EnsureCreated();
    }

    public IActionResult Index(int maxPriority = 2, bool isDone = false)
    {
        var model = _ToDoContext!.ToDo!.ToList();
        ViewData["maxPriority"] = maxPriority;
        ViewData["isDone"] = isDone;
        return View(model);
    }

Dodawanie klasy ViewComponent

Dodaj klasę ViewComponent do elementu ViewComponents/PriorityListViewComponent.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents;

public class PriorityListViewComponent : ViewComponent
{
    private readonly ToDoContext db;

    public PriorityListViewComponent(ToDoContext context) => db = context;

    public async Task<IViewComponentResult> InvokeAsync(
                                            int maxPriority, bool isDone)
    {
        var items = await GetItemsAsync(maxPriority, isDone);
        return View(items);
    }

    private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
    {
        return db!.ToDo!.Where(x => x.IsDone == isDone &&
                             x.Priority <= maxPriority).ToListAsync();
    }
}

Uwagi dotyczące kodu:

  • Klasy składników widoku mogą być zawarte w dowolnym folderze w projekcie.

  • Ponieważ nazwa klasy PriorityListViewComponent kończy się sufiksem ViewComponent, środowisko uruchomieniowe używa ciągu PriorityList podczas odwoływania się do składnika klasy z widoku.

  • Atrybut [ViewComponent] może zmienić nazwę używaną do odwołowania się do składnika widoku. Na przykład klasa mogła mieć nazwę XYZ z następującym [ViewComponent] atrybutem:

    [ViewComponent(Name = "PriorityList")]
       public class XYZ : ViewComponent
    
  • Atrybut [ViewComponent] w poprzednim kodzie informuje selektora składników widoku do użycia:

    • Nazwa PriorityList podczas wyszukiwania widoków skojarzonych z składnikiem
    • Ciąg "PriorityList" podczas odwoływania się do składnika klasy z widoku.
  • Składnik używa iniekcji zależności, aby udostępnić kontekst danych.

  • InvokeAsync Uwidacznia metodę, którą można wywołać z widoku, i może przyjmować dowolną liczbę argumentów.

  • Metoda InvokeAsync zwraca zestaw ToDo elementów spełniających isDone parametry i maxPriority .

Tworzenie widoku składnika Razor

  • Utwórz folder Views/Shared/Components. Ten folder musi mieć nazwę Components.

  • Utwórz folder Views/Shared/Components/PriorityList. Ta nazwa folderu musi być zgodna z nazwą klasy składnika widoku lub nazwą klasy minus sufiks. ViewComponent Jeśli atrybut jest używany, nazwa klasy musi być zgodna z oznaczeniem atrybutu.

  • Views/Shared/Components/PriorityList/Default.cshtmlRazor Utwórz widok:

    @model IEnumerable<ViewComponentSample.Models.TodoItem>
    
    <h3>Priority Items</h3>
    <ul>
        @foreach (var todo in Model)
        {
            <li>@todo.Name</li>
        }
    </ul>
    

    Widok Razor przyjmuje listę TodoItem i wyświetla je. Jeśli metoda składnika InvokeAsync widoku nie przekazuje nazwy widoku, wartość Domyślna jest używana dla nazwy widoku zgodnie z konwencją. Aby zastąpić domyślny styl określonego kontrolera, dodaj widok do folderu widoku specyficznego dla kontrolera (na przykład Views/ToDo/Components/PriorityList/Default.cshtml)..

    Jeśli składnik widoku jest specyficzny dla kontrolera, można go dodać do folderu specyficznego dla kontrolera. Na przykład Views/ToDo/Components/PriorityList/Default.cshtml jest specyficzny dla kontrolera.

  • div Dodaj element zawierający wywołanie składnika listy priorytetów w dolnej części Views/ToDo/index.cshtml pliku:

    </table>
    
    <div>
        Maximum Priority: @ViewData["maxPriority"] <br />
        Is Complete:  @ViewData["isDone"]
        @await Component.InvokeAsync("PriorityList",
                         new { 
                             maxPriority =  ViewData["maxPriority"],
                             isDone = ViewData["isDone"]  }
                         )
    </div>
    

Znacznik @await Component.InvokeAsync pokazuje składnię wywoływania składników widoku. Pierwszym argumentem jest nazwa składnika, który chcemy wywołać lub wywołać. Kolejne parametry są przekazywane do składnika. InvokeAsync może przyjmować dowolną liczbę argumentów.

Testowanie aplikacji. Na poniższej ilustracji przedstawiono listę Zadań do wykonania i elementy priorytetu:

todo list and priority items

Składnik widoku można wywołać bezpośrednio z kontrolera:

public IActionResult IndexVC(int maxPriority = 2, bool isDone = false)
{
    return ViewComponent("PriorityList",
        new { 
           maxPriority = maxPriority,
           isDone = isDone
        });
}

priority items from IndexVC action

Określanie nazwy składnika widoku

Składnik widoku złożonego może wymagać określenia widoku innego niż domyślny w niektórych warunkach. Poniższy kod pokazuje, jak określić widok "PVC" z InvokeAsync metody . Zaktualizuj metodę InvokeAsyncPriorityListViewComponent w klasie .

public async Task<IViewComponentResult> InvokeAsync(
                                           int maxPriority, bool isDone)
{
    string MyView = "Default";
    // If asking for all completed tasks, render with the "PVC" view.
    if (maxPriority > 3 && isDone == true)
    {
        MyView = "PVC";
    }
    var items = await GetItemsAsync(maxPriority, isDone);
    return View(MyView, items);
}

Views/Shared/Components/PriorityList/Default.cshtml Skopiuj plik do widoku o nazwie Views/Shared/Components/PriorityList/PVC.cshtml. Dodaj nagłówek, aby wskazać, że widok PVC jest używany.

@model IEnumerable<ViewComponentSample.Models.TodoItem>

<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
    @foreach (var todo in Model)
    {
        <li>@todo.Name</li>
    }
</ul>

Uruchom aplikację i sprawdź widok PVC.

Priority View Component

Jeśli widok PVC nie jest renderowany, sprawdź, czy składnik widoku o priorytecie 4 lub wyższym jest wywoływany.

Badanie ścieżki widoku

  • Zmień parametr priorytetu na trzy lub mniej, aby widok priorytetu nie został zwrócony.

  • Tymczasowo zmień nazwę elementu na Views/ToDo/Components/PriorityList/Default.cshtml1Default.cshtml.

  • Przetestuj aplikację, wystąpi następujący błąd:

    An unhandled exception occurred while processing the request.
    InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched:
    /Views/ToDo/Components/PriorityList/Default.cshtml
    /Views/Shared/Components/PriorityList/Default.cshtml
    
  • Skopiuj folder Views/ToDo/Components/PriorityList/1Default.cshtml do folderu Views/Shared/Components/PriorityList/Default.cshtml.

  • Dodaj znaczniki do widoku składników udostępnionego widoku zadań do wykonania, aby wskazać, że widok pochodzi z folderu Udostępnione.

  • Przetestuj widok składników udostępnionych .

ToDo output with Shared component view

Unikaj zakodowanych ciągów

W przypadku bezpieczeństwa czasu kompilacji zastąp nazwę składnika widoku zakodowanego na podstawie kodu nazwą klasy. Zaktualizuj plik PriorityListViewComponent.cs, aby nie używać sufiksu "ViewComponent":

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents;

public class PriorityList : ViewComponent
{
    private readonly ToDoContext db;

    public PriorityList(ToDoContext context)
    {
        db = context;
    }

    public async Task<IViewComponentResult> InvokeAsync(
                                               int maxPriority, bool isDone)
    {
        var items = await GetItemsAsync(maxPriority, isDone);
        return View(items);
    }

    private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
    {
        return db!.ToDo!.Where(x => x.IsDone == isDone &&
                             x.Priority <= maxPriority).ToListAsync();
    }
}

Plik widoku :

</table>

<div>
    Testing nameof(PriorityList) <br />

    Maxium Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync(nameof(PriorityList),
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Przeciążenie Component.InvokeAsync metody, która przyjmuje typ CLR, używa typeof operatora :

</table>

<div>
    Testing typeof(PriorityList) <br />

    Maxium Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync(typeof(PriorityList),
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Wykonywanie pracy synchronicznej

Platforma obsługuje wywoływanie metody synchronicznej, jeśli praca asynchroniczna Invoke nie jest wymagana. Poniższa metoda tworzy synchroniczny Invoke składnik widoku:

using Microsoft.AspNetCore.Mvc;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents
{
    public class PriorityListSync : ViewComponent
    {
        private readonly ToDoContext db;

        public PriorityListSync(ToDoContext context)
        {
            db = context;
        }

        public IViewComponentResult Invoke(int maxPriority, bool isDone)
        {
 
            var x = db!.ToDo!.Where(x => x.IsDone == isDone &&
                                  x.Priority <= maxPriority).ToList();
            return View(x);
        }
    }
}

Plik składnika Razor widoku:

<div>
    Testing nameof(PriorityList) <br />

    Maxium Priority: @ViewData["maxPriority"] <br />
    Is Complete:  @ViewData["isDone"]
    @await Component.InvokeAsync(nameof(PriorityListSync),
                     new { 
                         maxPriority =  ViewData["maxPriority"],
                         isDone = ViewData["isDone"]  }
                     )
</div>

Składnik widoku jest wywoływany w Razor pliku (na przykład Views/Home/Index.cshtml) przy użyciu jednego z następujących metod:

Aby użyć podejścia, wywołaj metodę IViewComponentHelperComponent.InvokeAsync:

@await Component.InvokeAsync(nameof(PriorityList),
                             new { maxPriority = 4, isDone = true })

Aby użyć pomocnika tagów, zarejestruj zestaw zawierający składnik widoku przy użyciu @addTagHelper dyrektywy (składnik widoku znajduje się w zestawie o nazwie MyWebApp):

@addTagHelper *, MyWebApp

Użyj pomocnika tagu składnika widoku w Razor pliku znaczników:

<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>

Sygnatura PriorityList.Invoke metody metody jest synchroniczna, ale Razor znajduje i wywołuje metodę w Component.InvokeAsync pliku znaczników.

Dodatkowe zasoby

Wyświetl lub pobierz przykładowy kod (jak pobrać)

Składniki widoku

Składniki widoku są podobne do widoków częściowych, ale są znacznie bardziej zaawansowane. Składniki widoku nie używają powiązania modelu i zależą tylko od danych dostarczonych podczas wywoływania. Ten artykuł został napisany przy użyciu kontrolerów i widoków, ale składniki wyświetlania również współpracują ze stronami Razor .

Składnik widoku:

  • Renderuje fragment, a nie całą odpowiedź.
  • Obejmuje te same kwestie związane z separacją i korzyściami z testowania znalezionymi między kontrolerem a widokiem.
  • Może mieć parametry i logikę biznesową.
  • Jest zwykle wywoływany ze strony układu.

Składniki widoku są przeznaczone w dowolnym miejscu, w którym logika renderowania wielokrotnego użytku jest zbyt złożona dla widoku częściowego, takiego jak:

  • Menu nawigacji dynamicznej
  • Tagowanie chmury (gdzie wysyła zapytanie do bazy danych)
  • Panel logowania
  • Koszyk
  • Ostatnio opublikowane artykuły
  • Zawartość paska bocznego w typowym blogu
  • Panel logowania, który będzie renderowany na każdej stronie i wyświetla linki do wylogowania lub logowania, w zależności od stanu logowania użytkownika

Składnik widoku składa się z dwóch części: klasy (zazwyczaj pochodzącej z ViewComponentklasy ) i zwracany wynik (zazwyczaj widok). Podobnie jak kontrolery, składnik widoku może być poco, ale większość deweloperów korzysta z metod i właściwości dostępnych przez wyprowadzanie z ViewComponentklasy .

Podczas rozważania, czy wyświetlanie składników spełnia specyfikacje aplikacji, rozważ użycie Razor składników. Razor składniki łączą również znaczniki z kodem C#, aby tworzyć jednostki interfejsu użytkownika wielokrotnego użytku. Razor składniki są zaprojektowane pod kątem produktywności deweloperów podczas zapewniania logiki i kompozycji interfejsu użytkownika po stronie klienta. Aby uzyskać więcej informacji, zobacz ASP.NET Podstawowe Razor składniki. Aby uzyskać informacje na temat dołączania Razor składników do aplikacji MVC lub Razor Pages, zobacz Prerender i integrowanie składników ASP.NET CoreRazor.

Tworzenie składnika widoku

Ta sekcja zawiera ogólne wymagania dotyczące tworzenia składnika widoku. W dalszej części artykułu szczegółowo sprawdzimy każdy krok i utworzymy składnik widoku.

Klasa składników widoku

Klasę składników widoku można utworzyć za pomocą dowolnego z następujących elementów:

  • Wyprowadzanie z widokuComponent
  • Dekorowanie klasy za pomocą atrybutu [ViewComponent] lub wyprowadzanie z klasy z atrybutem [ViewComponent]
  • Tworzenie klasy, w której nazwa kończy się sufiksem ViewComponent

Podobnie jak kontrolery, składniki widoku muszą być publiczne, niezagnieżdżone i nie abstrakcyjne klasy. Nazwa składnika widoku to nazwa klasy z usuniętym sufiksem "ViewComponent". Można go również jawnie określić przy użyciu ViewComponentAttribute.Name właściwości .

Klasa składników widoku:

  • W pełni obsługuje wstrzykiwanie zależności konstruktora
  • Nie bierze udziału w cyklu życia kontrolera, co oznacza, że nie można używać filtrów w składniku widoku

Aby zatrzymać klasę, która ma sufiks ViewComponent bez uwzględniania wielkości liter, jest traktowana jako składnik widoku, udekoruj klasę za pomocą atrybutu [NonViewComponent]:

[NonViewComponent]
public class ReviewComponent
{
    // ...

Wyświetlanie metod składników

Składnik widoku definiuje logikę InvokeAsync w metodzie zwracającej metodę Task<IViewComponentResult> lub w metodzie synchronicznej Invoke zwracającej IViewComponentResultelement . Parametry pochodzą bezpośrednio z wywołania składnika widoku, a nie z powiązania modelu. Składnik widoku nigdy nie obsługuje bezpośrednio żądania. Zazwyczaj składnik widoku inicjuje model i przekazuje go do widoku, wywołując metodę View . Podsumowując, wyświetl metody składników:

  • Zdefiniuj metodę InvokeAsync zwracającą metodę Task<IViewComponentResult> synchroniczną Invoke lub zwracającą IViewComponentResultwartość .
  • Zazwyczaj inicjuje model i przekazuje go do widoku, wywołując metodę ViewComponentView .
  • Parametry pochodzą z metody wywołującej, a nie z protokołu HTTP. Nie ma powiązania modelu.
  • Nie są dostępne bezpośrednio jako punkt końcowy HTTP. Są one wywoływane z kodu (zwykle w widoku). Składnik widoku nigdy nie obsługuje żądania.
  • Są przeciążone podpisem, a nie wszelkimi szczegółami z bieżącego żądania HTTP.

Wyświetlanie ścieżki wyszukiwania

Środowisko uruchomieniowe wyszukuje widok w następujących ścieżkach:

  • /Views/{Nazwa kontrolera}/Składniki/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Views/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Pages/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku}
  • /Areas/{Nazwa obszaru}/Widoki/Udostępnione/Składniki/{Wyświetl nazwę składnika}/{Nazwa widoku}

Ścieżka wyszukiwania dotyczy projektów przy użyciu kontrolerów i widoków i Razor stron.

Domyślna nazwa widoku składnika widoku to Domyślna, co oznacza, że plik widoku będzie zazwyczaj miał nazwę Default.cshtml. Podczas tworzenia wyniku składnika widoku lub wywoływania View metody można określić inną nazwę widoku.

Zalecamy nadanie nazwy pliku Default.cshtml widoku i użycie ścieżki Views/Shared/Components/{Wyświetl nazwę składnika}/{Nazwa widoku} . Składnik PriorityList widoku używany w tym przykładzie jest używany Views/Shared/Components/PriorityList/Default.cshtml dla widoku składnika widoku.

Dostosowywanie ścieżki wyszukiwania widoku

Aby dostosować ścieżkę wyszukiwania widoku, zmodyfikuj RazorViewLocationFormats kolekcję . Aby na przykład wyszukać widoki w ścieżce "/Components/{Wyświetl nazwę składnika}/{Nazwa widoku}", dodaj nowy element do kolekcji:

services.AddMvc()
    .AddRazorOptions(options =>
    {
        options.ViewLocationFormats.Add("/{0}.cshtml");
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

W poprzednim kodzie symbol zastępczy "{0}" reprezentuje ścieżkę "Components/{View Component Name}/{View Component Name}/{View Name}".

Wywoływanie składnika widoku

Aby użyć składnika widoku, wywołaj następujące elementy w widoku:

@await Component.InvokeAsync("Name of view component", {Anonymous Type Containing Parameters})

Parametry zostaną przekazane do InvokeAsync metody . Składnik PriorityList widoku opracowany w artykule jest wywoływany z Views/ToDo/Index.cshtml pliku widoku. W poniższych metoda jest wywoływana InvokeAsync z dwoma parametrami:

@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })

Wywoływanie składnika widoku jako pomocnika tagów

W przypadku ASP.NET Core 1.1 i nowszych można wywołać składnik widoku jako pomocnik tagów:

<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>

Parametry klasy i metody Pascal cased dla pomocników tagów są tłumaczone na ich przypadek kebab. Pomocnik tagów do wywoływania składnika widoku używa <vc></vc> elementu . Składnik widoku jest określony w następujący sposób:

<vc:[view-component-name]
  parameter1="parameter1 value"
  parameter2="parameter2 value">
</vc:[view-component-name]>

Aby użyć składnika widoku jako pomocnika tagów, zarejestruj zestaw zawierający składnik widoku przy użyciu @addTagHelper dyrektywy . Jeśli składnik widoku znajduje się w zestawie o nazwie MyWebApp, dodaj następującą dyrektywę _ViewImports.cshtml do pliku:

@addTagHelper *, MyWebApp

Składnik widoku można zarejestrować jako pomocnik tagów do dowolnego pliku, który odwołuje się do składnika widoku. Aby uzyskać więcej informacji na temat rejestrowania pomocników tagów, zobacz Zarządzanie zakresem pomocnika tagów.

Metoda InvokeAsync używana w tym samouczku:

@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })

W znacznikach pomocnika tagów:

<vc:priority-list max-priority="2" is-done="false">
</vc:priority-list>

W powyższym PriorityList przykładzie składnik widoku staje się .priority-list Parametry składnika widoku są przekazywane jako atrybuty w przypadku kebab.

Wywoływanie składnika widoku bezpośrednio z kontrolera

Składniki widoku są zwykle wywoływane z widoku, ale można wywołać je bezpośrednio z metody kontrolera. Chociaż składniki widoku nie definiują punktów końcowych, takich jak kontrolery, można łatwo zaimplementować akcję kontrolera zwracającą zawartość elementu ViewComponentResult.

W tym przykładzie składnik widoku jest wywoływany bezpośrednio z kontrolera:

public IActionResult IndexVC()
{
    return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}

Przewodnik: tworzenie prostego składnika widoku

Pobierz, skompiluj i przetestuj kod początkowy. Jest to prosty projekt z kontrolerem ToDo , który wyświetla listę elementów zadań do wykonania .

List of ToDos

Dodawanie klasy ViewComponent

Utwórz folder ViewComponents i dodaj następującą PriorityListViewComponent klasę:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents
{
    public class PriorityListViewComponent : ViewComponent
    {
        private readonly ToDoContext db;

        public PriorityListViewComponent(ToDoContext context)
        {
            db = context;
        }

        public async Task<IViewComponentResult> InvokeAsync(
        int maxPriority, bool isDone)
        {
            var items = await GetItemsAsync(maxPriority, isDone);
            return View(items);
        }
        private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
        {
            return db.ToDo.Where(x => x.IsDone == isDone &&
                                 x.Priority <= maxPriority).ToListAsync();
        }
    }
}

Uwagi dotyczące kodu:

  • Klasy składników widoku mogą być zawarte w dowolnym folderze w projekcie.

  • Ponieważ nazwa klasy PriorityListViewComponent kończy się sufiksem ViewComponent, środowisko uruchomieniowe używa ciągu PriorityList podczas odwoływania się do składnika klasy z widoku.

  • Atrybut [ViewComponent] może zmienić nazwę używaną do odwołowania się do składnika widoku. Na przykład klasa mogła mieć nazwę XYZ z atrybutem ViewComponent :

    [ViewComponent(Name = "PriorityList")]
       public class XYZ : ViewComponent
    
  • Atrybut [ViewComponent] w poprzednim kodzie informuje selektora składników widoku do użycia:

    • Nazwa PriorityList podczas wyszukiwania widoków skojarzonych z składnikiem
    • Ciąg "PriorityList" podczas odwoływania się do składnika klasy z widoku.
  • Składnik używa iniekcji zależności, aby udostępnić kontekst danych.

  • InvokeAsync Uwidacznia metodę, którą można wywołać z widoku, i może przyjmować dowolną liczbę argumentów.

  • Metoda InvokeAsync zwraca zestaw ToDo elementów spełniających isDone parametry i maxPriority .

Tworzenie widoku składnika Razor

  • Utwórz folder Views/Shared/Components. Ten folder musi mieć nazwę Components.

  • Utwórz folder Views/Shared/Components/PriorityList. Ta nazwa folderu musi być zgodna z nazwą klasy składnika widoku lub nazwą klasy minus sufiksem (jeśli przestrzegamy konwencji i użyto sufiksu ViewComponent w nazwie klasy). Jeśli użyto atrybutu ViewComponent , nazwa klasy musi być zgodna z oznaczeniem atrybutu.

  • Views/Shared/Components/PriorityList/Default.cshtmlRazor Utwórz widok:

    @model IEnumerable<ViewComponentSample.Models.TodoItem>
    
    <h3>Priority Items</h3>
    <ul>
        @foreach (var todo in Model)
        {
            <li>@todo.Name</li>
        }
    </ul>
    

    Widok Razor przyjmuje listę TodoItem i wyświetla je. Jeśli metoda składnika InvokeAsync widoku nie przekazuje nazwy widoku (jak w naszym przykładzie), wartość domyślna jest używana dla nazwy widoku według konwencji. W dalszej części samouczka pokażę, jak przekazać nazwę widoku. Aby zastąpić domyślny styl określonego kontrolera, dodaj widok do folderu widoku specyficznego dla kontrolera (na przykład Views/ToDo/Components/PriorityList/Default.cshtml)..

    Jeśli składnik widoku jest specyficzny dla kontrolera, możesz dodać go do folderu specyficznego dla kontrolera (Views/ToDo/Components/PriorityList/Default.cshtml).

  • div Dodaj element zawierający wywołanie składnika listy priorytetów w dolnej części Views/ToDo/index.cshtml pliku:

    </table>
    <div>
        @await Component.InvokeAsync("PriorityList", new { maxPriority = 2, isDone = false })
    </div>
    

Znacznik @await Component.InvokeAsync pokazuje składnię wywoływania składników widoku. Pierwszym argumentem jest nazwa składnika, który chcemy wywołać lub wywołać. Kolejne parametry są przekazywane do składnika. InvokeAsync może przyjmować dowolną liczbę argumentów.

Testowanie aplikacji. Na poniższej ilustracji przedstawiono listę Zadań do wykonania i elementy priorytetu:

todo list and priority items

Składnik widoku można również wywołać bezpośrednio z kontrolera:

public IActionResult IndexVC()
{
    return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}

priority items from IndexVC action

Określanie nazwy widoku

Składnik widoku złożonego może wymagać określenia widoku innego niż domyślny w niektórych warunkach. Poniższy kod pokazuje, jak określić widok "PVC" z InvokeAsync metody . Zaktualizuj metodę InvokeAsyncPriorityListViewComponent w klasie .

public async Task<IViewComponentResult> InvokeAsync(
    int maxPriority, bool isDone)
{
    string MyView = "Default";
    // If asking for all completed tasks, render with the "PVC" view.
    if (maxPriority > 3 && isDone == true)
    {
        MyView = "PVC";
    }
    var items = await GetItemsAsync(maxPriority, isDone);
    return View(MyView, items);
}

Views/Shared/Components/PriorityList/Default.cshtml Skopiuj plik do widoku o nazwie Views/Shared/Components/PriorityList/PVC.cshtml. Dodaj nagłówek, aby wskazać, że widok PVC jest używany.

@model IEnumerable<ViewComponentSample.Models.TodoItem>

<h2> PVC Named Priority Component View</h2>
<h4>@ViewBag.PriorityMessage</h4>
<ul>
    @foreach (var todo in Model)
    {
        <li>@todo.Name</li>
    }
</ul>

Aktualizacja Views/ToDo/Index.cshtml:

@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })

Uruchom aplikację i sprawdź widok PVC.

Priority View Component

Jeśli widok PVC nie jest renderowany, sprawdź, czy wywołujesz składnik widoku o priorytecie 4 lub wyższym.

Badanie ścieżki widoku

  • Zmień parametr priorytetu na trzy lub mniej, aby widok priorytetu nie został zwrócony.

  • Tymczasowo zmień nazwę elementu na Views/ToDo/Components/PriorityList/Default.cshtml1Default.cshtml.

  • Przetestuj aplikację. Zostanie wyświetlony następujący błąd:

    An unhandled exception occurred while processing the request.
    InvalidOperationException: The view 'Components/PriorityList/Default' wasn't found. The following locations were searched:
    /Views/ToDo/Components/PriorityList/Default.cshtml
    /Views/Shared/Components/PriorityList/Default.cshtml
    EnsureSuccessful
    
  • Skopiuj folder Views/ToDo/Components/PriorityList/1Default.cshtml do folderu Views/Shared/Components/PriorityList/Default.cshtml.

  • Dodaj znaczniki do widoku składników udostępnionego widoku zadań do wykonania, aby wskazać, że widok pochodzi z folderu Udostępnione.

  • Przetestuj widok składników udostępnionych .

ToDo output with Shared component view

Unikanie zakodowanych ciągów

Jeśli chcesz, aby bezpieczeństwo czasu kompilacji było możliwe, możesz zastąpić nazwę składnika widoku zakodowanego na podstawie kodu nazwą klasy. Utwórz składnik widoku bez sufiksu "ViewComponent":

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents
{
    public class PriorityList : ViewComponent
    {
        private readonly ToDoContext db;

        public PriorityList(ToDoContext context)
        {
            db = context;
        }

        public async Task<IViewComponentResult> InvokeAsync(
        int maxPriority, bool isDone)
        {
            var items = await GetItemsAsync(maxPriority, isDone);
            return View(items);
        }
        private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
        {
            return db.ToDo.Where(x => x.IsDone == isDone &&
                                 x.Priority <= maxPriority).ToListAsync();
        }
    }
}

Dodaj instrukcję using do Razor pliku widoku i użyj nameof operatora :

@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>

    <h2>ToDo nameof</h2>
    <!-- Markup removed for brevity.  -->

    <div>

        @*
            Note: 
            To use the below line, you need to #define no_suffix in ViewComponents/PriorityList.cs or it won't compile.
            By doing so it will cause a problem to index as there will be multiple viewcomponents 
            with the same name after the compiler removes the suffix "ViewComponent"
        *@

        @*@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })*@
    </div>

Można użyć przeciążenia Component.InvokeAsync metody, która przyjmuje typ CLR. Pamiętaj, aby użyć typeof operatora w tym przypadku:

@using ViewComponentSample.Models
@using ViewComponentSample.ViewComponents
@model IEnumerable<TodoItem>

<h2>ToDo typeof</h2>
<!-- Markup removed for brevity.  -->

<div>
    @await Component.InvokeAsync(typeof(PriorityListViewComponent), new { maxPriority = 4, isDone = true })
</div>

Wykonywanie pracy synchronicznej

Platforma obsługuje wywoływanie metody synchronicznej Invoke , jeśli nie trzeba wykonywać pracy asynchronicznej. Poniższa metoda tworzy synchroniczny Invoke składnik widoku:

public class PriorityList : ViewComponent
{
    public IViewComponentResult Invoke(int maxPriority, bool isDone)
    {
        var items = new List<string> { $"maxPriority: {maxPriority}", $"isDone: {isDone}" };
        return View(items);
    }
}

Plik składnika Razor widoku zawiera listę ciągów przekazanych do Invoke metody (Views/Home/Components/PriorityList/Default.cshtml):

@model List<string>

<h3>Priority Items</h3>
<ul>
    @foreach (var item in Model)
    {
        <li>@item</li>
    }
</ul>

Składnik widoku jest wywoływany w Razor pliku (na przykład Views/Home/Index.cshtml) przy użyciu jednego z następujących metod:

Aby użyć podejścia, wywołaj metodę IViewComponentHelperComponent.InvokeAsync:

@await Component.InvokeAsync(nameof(PriorityList), new { maxPriority = 4, isDone = true })

Aby użyć pomocnika tagów, zarejestruj zestaw zawierający składnik widoku przy użyciu @addTagHelper dyrektywy (składnik widoku znajduje się w zestawie o nazwie MyWebApp):

@addTagHelper *, MyWebApp

Użyj pomocnika tagu składnika widoku w Razor pliku znaczników:

<vc:priority-list max-priority="999" is-done="false">
</vc:priority-list>

Sygnatura PriorityList.Invoke metody metody jest synchroniczna, ale Razor znajduje i wywołuje metodę w Component.InvokeAsync pliku znaczników.

Wszystkie parametry składnika widoku są wymagane

Każdy parametr w składniku widoku jest wymaganym atrybutem. Zobacz ten problem z usługą GitHub. Jeśli pominięto jakikolwiek parametr:

  • Sygnatura InvokeAsync metody nie będzie zgodna, dlatego metoda nie zostanie wykonana.
  • Element ViewComponent nie będzie renderować żadnych znaczników.
  • Nie zostaną rzucone żadne błędy.

Dodatkowe zasoby