Injeksi dependensi ke dalam tampilan di ASP.NET Core

ASP.NET Core mendukung injeksi dependensi ke dalam tampilan. Ini dapat berguna untuk layanan khusus tampilan, seperti pelokalan atau data yang diperlukan hanya untuk mengisi elemen tampilan. Sebagian besar tampilan tampilan data harus diteruskan dari pengontrol.

Melihat atau mengunduh kode sampel (cara mengunduh)

Injeksi konfigurasi

Nilai dalam file pengaturan, seperti appsettings.json dan appsettings.Development.json, dapat disuntikkan ke dalam tampilan. appsettings.Development.json Pertimbangkan dari kode sampel:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "MyRoot": {
    "MyParent": {
      "MyChildName": "Joe"
    }
  }
}

Markup berikut menampilkan nilai konfigurasi dalam Razor tampilan Halaman:

@page
@model PrivacyModel
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
    ViewData["Title"] = "Privacy RP";
}
<h1>@ViewData["Title"]</h1>

<p>PR Privacy</p>

<h2>
   MyRoot:MyParent:MyChildName: @Configuration["MyRoot:MyParent:MyChildName"]
</h2>

Markup berikut menampilkan nilai konfigurasi dalam tampilan MVC:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
    ViewData["Title"] = "Privacy MVC";
}
<h1>@ViewData["Title"]</h1>

<p>MVC Use this page to detail your site's privacy policy.</p>

<h2>
   MyRoot:MyParent:MyChildName: @Configuration["MyRoot:MyParent:MyChildName"]
</h2>

Untuk informasi selengkapnya, lihat Konfigurasi di ASP.NET Core

Injeksi layanan

Layanan dapat disuntikkan ke dalam tampilan menggunakan direktif @inject .

@using System.Threading.Tasks
@using ViewInjectSample.Model
@using ViewInjectSample.Model.Services
@model IEnumerable<ToDoItem>
@inject StatisticsService StatsService
<!DOCTYPE html>
<html>
<head>
    <title>To Do Items</title>
</head>
<body>
    <div>
        <h1>To Do Items</h1>
        <ul>
            <li>Total Items: @StatsService.GetCount()</li>
            <li>Completed: @StatsService.GetCompletedCount()</li>
            <li>Avg. Priority: @StatsService.GetAveragePriority()</li>
        </ul>
        <table>
            <tr>
                <th>Name</th>
                <th>Priority</th>
                <th>Is Done?</th>
            </tr>
            @foreach (var item in Model)
            {
                <tr>
                    <td>@item.Name</td>
                    <td>@item.Priority</td>
                    <td>@item.IsDone</td>
                </tr>
            }
        </table>
    </div>
</body>
</html>

Tampilan ini menampilkan daftar ToDoItem instans, bersama dengan ringkasan yang menunjukkan statistik keseluruhan. Ringkasan diisi dari yang disuntikkan StatisticsService. Layanan ini terdaftar untuk injeksi dependensi di ConfigureServices :Program.cs

using ViewInjectSample.Helpers;
using ViewInjectSample.Infrastructure;
using ViewInjectSample.Interfaces;
using ViewInjectSample.Model.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

builder.Services.AddTransient<IToDoItemRepository, ToDoItemRepository>();
builder.Services.AddTransient<StatisticsService>();
builder.Services.AddTransient<ProfileOptionsService>();
builder.Services.AddTransient<MyHtmlHelper>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.MapRazorPages();

app.MapDefaultControllerRoute();


app.Run();

StatisticsService melakukan beberapa perhitungan pada kumpulan ToDoItem instans, yang diaksesnya melalui repositori:

using System.Linq;
using ViewInjectSample.Interfaces;

namespace ViewInjectSample.Model.Services
{
    public class StatisticsService
    {
        private readonly IToDoItemRepository _toDoItemRepository;

        public StatisticsService(IToDoItemRepository toDoItemRepository)
        {
            _toDoItemRepository = toDoItemRepository;
        }

        public int GetCount()
        {
            return _toDoItemRepository.List().Count();
        }

        public int GetCompletedCount()
        {
            return _toDoItemRepository.List().Count(x => x.IsDone);
        }

        public double GetAveragePriority()
        {
            if (_toDoItemRepository.List().Count() == 0)
            {
                return 0.0;
            }

            return _toDoItemRepository.List().Average(x => x.Priority);
        }
    }
}

Repositori sampel menggunakan koleksi dalam memori. Implementasi dalam memori tidak boleh digunakan untuk himpunan data besar yang diakses dari jarak jauh.

Sampel menampilkan data dari model yang terikat ke tampilan dan layanan yang disuntikkan ke dalam tampilan:

To Do view listing total items, completed items, average priority, and a list of tasks with their priority levels and boolean values indicating completion.

Mengisi Data Pencarian

Injeksi tampilan dapat berguna untuk mengisi opsi dalam elemen UI, seperti daftar dropdown. Pertimbangkan formulir profil pengguna yang menyertakan opsi untuk menentukan jenis kelamin, status, dan preferensi lainnya. Merender formulir seperti itu menggunakan pendekatan standar mungkin memerlukan pengontrol atau Razor Halaman untuk:

  • Meminta layanan akses data untuk setiap set opsi.
  • Isi model atau ViewBag dengan setiap set opsi yang akan terikat.

Pendekatan alternatif menyuntikkan layanan langsung ke tampilan untuk mendapatkan opsi. Ini meminimalkan jumlah kode yang diperlukan oleh Pengontrol atau Halaman Pisau Cukur, memindahkan logika konstruksi elemen tampilan ini ke dalam tampilan itu sendiri. Tindakan pengontrol atau Razor Halaman untuk menampilkan formulir pengeditan profil hanya perlu meneruskan formulir instans profil:

using Microsoft.AspNetCore.Mvc;
using ViewInjectSample.Model;

namespace ViewInjectSample.Controllers;

public class ProfileController : Controller
{
    public IActionResult Index()
    {
        // A real app would up profile based on the user.
        var profile = new Profile()
        {
            Name = "Rick",
            FavColor = "Blue",
            Gender = "Male",
            State = new State("Ohio","OH")
        };
        return View(profile);
    }
}

Formulir HTML yang digunakan untuk memperbarui preferensi menyertakan daftar dropdown untuk tiga properti:

Update Profile view with a form allowing the entry of name, gender, state, and favorite Color.

Daftar ini diisi oleh layanan yang telah disuntikkan ke dalam tampilan:

@using System.Threading.Tasks
@using ViewInjectSample.Model.Services
@model ViewInjectSample.Model.Profile
@inject ProfileOptionsService Options
<!DOCTYPE html>
<html>
<head>
    <title>Update Profile</title>
</head>
<body>
<div>
    <h1>Update Profile</h1>
    Name: @Html.TextBoxFor(m => m.Name)
    <br/>
    Gender: @Html.DropDownList("Gender",
           Options.ListGenders().Select(g => 
                new SelectListItem() { Text = g, Value = g }))
    <br/>

    State: @Html.DropDownListFor(m => m.State!.Code,
           Options.ListStates().Select(s => 
                new SelectListItem() { Text = s.Name, Value = s.Code}))
    <br />

    Fav. Color: @Html.DropDownList("FavColor",
           Options.ListColors().Select(c => 
                new SelectListItem() { Text = c, Value = c }))
    </div>
</body>
</html>

ProfileOptionsService adalah layanan tingkat UI yang dirancang untuk menyediakan hanya data yang diperlukan untuk formulir ini:

namespace ViewInjectSample.Model.Services;

public class ProfileOptionsService
{
    public List<string> ListGenders()
    {
        // Basic sample
        return new List<string>() {"Female", "Male"};
    }

    public List<State> ListStates()
    {
        // Add a few states
        return new List<State>()
        {
            new State("Alabama", "AL"),
            new State("Alaska", "AK"),
            new State("Ohio", "OH")
        };
    }

    public List<string> ListColors()
    {
        return new List<string>() { "Blue","Green","Red","Yellow" };
    }
}

Perhatikan jenis yang tidak terdaftar melempar pengecualian saat runtime karena penyedia layanan secara internal dikueri melalui GetRequiredService.

Layanan Penggantian

Selain menyuntikkan layanan baru, teknik ini dapat digunakan untuk mengambil alih layanan yang sebelumnya disuntikkan pada halaman. Gambar di bawah ini menunjukkan semua bidang yang tersedia di halaman yang digunakan dalam contoh pertama:

Intellisense contextual menu on a typed @ symbol listing Html, Component, StatsService, and Url fields

Bidang default mencakup Html, Component, dan Url. Untuk mengganti Pembantu HTML default dengan versi kustom, gunakan @inject:

@using System.Threading.Tasks
@using ViewInjectSample.Helpers
@inject MyHtmlHelper Html
<!DOCTYPE html>
<html>
<head>
    <title>My Helper</title>
</head>
<body>
    <div>
        Test: @Html.Value
    </div>
</body>
</html>

Lihat Juga

ASP.NET Core mendukung injeksi dependensi ke dalam tampilan. Ini dapat berguna untuk layanan khusus tampilan, seperti pelokalan atau data yang diperlukan hanya untuk mengisi elemen tampilan. Anda harus mencoba mempertahankan pemisahan kekhawatiran antara pengontrol dan tampilan Anda. Sebagian besar data yang ditampilkan tampilan Anda harus diteruskan dari pengontrol.

Melihat atau mengunduh kode sampel (cara mengunduh)

Injeksi konfigurasi

appsettings.json nilai dapat disuntikkan langsung ke dalam tampilan.

appsettings.json Contoh file:

{
   "root": {
      "parent": {
         "child": "myvalue"
      }
   }
}

Sintaks untuk @inject: @inject <type> <name>

Contoh menggunakan @inject:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
   string myValue = Configuration["root:parent:child"];
   ...
}

Injeksi layanan

Layanan dapat disuntikkan ke dalam tampilan menggunakan direktif @inject . Anda dapat menganggap @inject sebagai menambahkan properti ke tampilan, dan mengisi properti menggunakan DI.

@using System.Threading.Tasks
@using ViewInjectSample.Model
@using ViewInjectSample.Model.Services
@model IEnumerable<ToDoItem>
@inject StatisticsService StatsService
<!DOCTYPE html>
<html>
<head>
    <title>To Do Items</title>
</head>
<body>
    <div>
        <h1>To Do Items</h1>
        <ul>
            <li>Total Items: @StatsService.GetCount()</li>
            <li>Completed: @StatsService.GetCompletedCount()</li>
            <li>Avg. Priority: @StatsService.GetAveragePriority()</li>
        </ul>
        <table>
            <tr>
                <th>Name</th>
                <th>Priority</th>
                <th>Is Done?</th>
            </tr>
            @foreach (var item in Model)
            {
                <tr>
                    <td>@item.Name</td>
                    <td>@item.Priority</td>
                    <td>@item.IsDone</td>
                </tr>
            }
        </table>
    </div>
</body>
</html>

Tampilan ini menampilkan daftar ToDoItem instans, bersama dengan ringkasan yang menunjukkan statistik keseluruhan. Ringkasan diisi dari yang disuntikkan StatisticsService. Layanan ini terdaftar untuk injeksi dependensi di ConfigureServices :Startup.cs

public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

StatisticsService melakukan beberapa perhitungan pada kumpulan ToDoItem instans, yang diaksesnya melalui repositori:

using System.Linq;
using ViewInjectSample.Interfaces;

namespace ViewInjectSample.Model.Services
{
    public class StatisticsService
    {
        private readonly IToDoItemRepository _toDoItemRepository;

        public StatisticsService(IToDoItemRepository toDoItemRepository)
        {
            _toDoItemRepository = toDoItemRepository;
        }

        public int GetCount()
        {
            return _toDoItemRepository.List().Count();
        }

        public int GetCompletedCount()
        {
            return _toDoItemRepository.List().Count(x => x.IsDone);
        }

        public double GetAveragePriority()
        {
            if (_toDoItemRepository.List().Count() == 0)
            {
                return 0.0;
            }

            return _toDoItemRepository.List().Average(x => x.Priority);
        }
    }
}

Repositori sampel menggunakan koleksi dalam memori. Implementasi yang ditunjukkan di atas (yang beroperasi pada semua data dalam memori) tidak disarankan untuk himpunan data besar yang diakses dari jarak jauh.

Sampel menampilkan data dari model yang terikat ke tampilan dan layanan yang disuntikkan ke dalam tampilan:

To Do view listing total items, completed items, average priority, and a list of tasks with their priority levels and boolean values indicating completion.

Mengisi Data Pencarian

Injeksi tampilan dapat berguna untuk mengisi opsi dalam elemen UI, seperti daftar dropdown. Pertimbangkan formulir profil pengguna yang menyertakan opsi untuk menentukan jenis kelamin, status, dan preferensi lainnya. Merender formulir seperti itu menggunakan pendekatan MVC standar akan mengharuskan pengontrol untuk meminta layanan akses data untuk setiap set opsi ini, lalu mengisi model atau ViewBag dengan setiap set opsi untuk terikat.

Pendekatan alternatif menyuntikkan layanan langsung ke tampilan untuk mendapatkan opsi. Ini meminimalkan jumlah kode yang diperlukan oleh pengontrol, memindahkan logika konstruksi elemen tampilan ini ke dalam tampilan itu sendiri. Tindakan pengontrol untuk menampilkan formulir pengeditan profil hanya perlu meneruskan formulir instans profil:

using Microsoft.AspNetCore.Mvc;
using ViewInjectSample.Model;

namespace ViewInjectSample.Controllers
{
    public class ProfileController : Controller
    {
        [Route("Profile")]
        public IActionResult Index()
        {
            // TODO: look up profile based on logged-in user
            var profile = new Profile()
            {
                Name = "Steve",
                FavColor = "Blue",
                Gender = "Male",
                State = new State("Ohio","OH")
            };
            return View(profile);
        }
    }
}

Formulir HTML yang digunakan untuk memperbarui preferensi ini menyertakan daftar dropdown untuk tiga properti:

Update Profile view with a form allowing the entry of name, gender, state, and favorite Color.

Daftar ini diisi oleh layanan yang telah disuntikkan ke dalam tampilan:

@using System.Threading.Tasks
@using ViewInjectSample.Model.Services
@model ViewInjectSample.Model.Profile
@inject ProfileOptionsService Options
<!DOCTYPE html>
<html>
<head>
    <title>Update Profile</title>
</head>
<body>
<div>
    <h1>Update Profile</h1>
    Name: @Html.TextBoxFor(m => m.Name)
    <br/>
    Gender: @Html.DropDownList("Gender",
           Options.ListGenders().Select(g => 
                new SelectListItem() { Text = g, Value = g }))
    <br/>

    State: @Html.DropDownListFor(m => m.State.Code,
           Options.ListStates().Select(s => 
                new SelectListItem() { Text = s.Name, Value = s.Code}))
    <br />

    Fav. Color: @Html.DropDownList("FavColor",
           Options.ListColors().Select(c => 
                new SelectListItem() { Text = c, Value = c }))
    </div>
</body>
</html>

ProfileOptionsService adalah layanan tingkat UI yang dirancang untuk menyediakan hanya data yang diperlukan untuk formulir ini:

using System.Collections.Generic;

namespace ViewInjectSample.Model.Services
{
    public class ProfileOptionsService
    {
        public List<string> ListGenders()
        {
            // keeping this simple
            return new List<string>() {"Female", "Male"};
        }

        public List<State> ListStates()
        {
            // a few states from USA
            return new List<State>()
            {
                new State("Alabama", "AL"),
                new State("Alaska", "AK"),
                new State("Ohio", "OH")
            };
        }

        public List<string> ListColors()
        {
            return new List<string>() { "Blue","Green","Red","Yellow" };
        }
    }
}

Penting

Jangan lupa untuk mendaftarkan jenis yang Anda minta melalui injeksi dependensi di Startup.ConfigureServices. Jenis yang tidak terdaftar melempar pengecualian saat runtime karena penyedia layanan secara internal dikueri melalui GetRequiredService.

Layanan Penggantian

Selain menyuntikkan layanan baru, teknik ini juga dapat digunakan untuk mengambil alih layanan yang sebelumnya disuntikkan pada halaman. Gambar di bawah ini menunjukkan semua bidang yang tersedia di halaman yang digunakan dalam contoh pertama:

Intellisense contextual menu on a typed @ symbol listing Html, Component, StatsService, and Url fields

Seperti yang Anda lihat, bidang default mencakup Html, , Componentdan Url (serta StatsService yang kami suntikkan). Jika misalnya Anda ingin mengganti Pembantu HTML default dengan pembantu HTML Anda sendiri, Anda dapat dengan mudah melakukannya menggunakan @inject:

@using System.Threading.Tasks
@using ViewInjectSample.Helpers
@inject MyHtmlHelper Html
<!DOCTYPE html>
<html>
<head>
    <title>My Helper</title>
</head>
<body>
    <div>
        Test: @Html.Value
    </div>
</body>
</html>

Jika Anda ingin memperluas layanan yang ada, Anda cukup menggunakan teknik ini sambil mewarisi dari atau membungkus implementasi yang ada dengan milik Anda sendiri.

Lihat Juga