Injektáž závislostí do zobrazení v ASP.NET Core

Od Steve Smith

ASP.NET Core podporuje injektáž závislostí do zobrazení. To může být užitečné pro zobrazení konkrétních služeb, jako je lokalizace nebo data vyžadované pouze pro naplnění prvků zobrazení. Měli byste se pokusit zachovat oddělení problémů mezi řadiči a zobrazeními. Většina dat, která zobrazení zobrazují, by se měla předá z kontroleru.

Zobrazení nebo stažení ukázkového kódu (stažení)

Injektáž konfigurace

appsettings.json Hodnoty lze vloženého přímo do zobrazení.

Příklad appsettings.json souboru:

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

Syntaxe pro @inject : @inject <type> <name>

Příklad s využitím @inject :

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

Injektáž služby

Službu lze pomocí direktivy vloženého do @inject zobrazení. Můžete si to myslít jako přidání vlastnosti do zobrazení a naplnění vlastnosti @inject pomocí objektu PRO.

@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>

Toto zobrazení zobrazuje seznam instancí spolu se ToDoItem souhrnem zobrazující celkové statistiky. Souhrn se vyplní z injektovaného souboru StatisticsService . Tato služba je zaregistrovaná pro injektáž závislostí ConfigureServices v souboru Startup.cs:

// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddTransient<IToDoItemRepository, ToDoItemRepository>();
    services.AddTransient<StatisticsService>();
    services.AddTransient<ProfileOptionsService>();

Provádí StatisticsService několik výpočtů na sadě instancí, ke kterým ToDoItem přistupuje prostřednictvím úložiště:

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);
        }
    }
}

Ukázkové úložiště používá kolekci v paměti. Výše uvedená implementace (která funguje se všemi daty v paměti) se nedoporučuje pro velké a vzdáleně přístupné datové sady.

Ukázka zobrazí data z modelu vázaného na zobrazení a službu vloženého do zobrazení:

To Do se seznamem celkových položek, dokončených položek, průměrné priority a seznamu úkolů s jejich úrovněmi priority a logickými hodnotami označujícími dokončení.

Naplnění vyhledávacích dat

Injektáž zobrazení může být užitečná k naplnění možností v prvcích uživatelského rozhraní, jako jsou rozevírací seznamy. Představte si profil uživatele, který obsahuje možnosti pro určení pohlaví, stavu a dalších preferencí. Vykreslení takového formuláře pomocí standardního přístupu MVC by vyžadovalo, aby kontroler vyžadoval služby přístupu k datům pro každou z těchto sad možností a pak doplní model nebo každou sadu možností, které mají být ViewBag svázány.

Alternativní přístup za účelem získání možností vloží služby přímo do zobrazení. Tím se minimalizuje množství kódu vyžadované kontroleru a přesune se tato logika konstrukce prvku zobrazení do samotného zobrazení. Akce kontroleru pro zobrazení formuláře pro úpravy profilu musí předat pouze formulář instanci profilu:

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);
        }
    }
}

Formulář HTML použitý k aktualizaci těchto předvoleb obsahuje rozevírací seznamy pro tři z vlastností:

Aktualizujte zobrazení profilu pomocí formuláře, který umožňuje zadání jména, pohlaví, státu a oblíbené barvy.

Tyto seznamy jsou naplněné službou, která byla do zobrazení vloženého:

@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>

je ProfileOptionsService služba na úrovni uživatelského rozhraní navržená tak, aby poskytovala pouze data potřebná pro tento formulář:

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" };
        }
    }
}

Důležité

Nezapomeňte zaregistrovat typy, které si vyžádáte prostřednictvím injektáže závislostí v Startup.ConfigureServices . Neregistrovaný typ vyvolá výjimku za běhu, protože poskytovatel služeb je interně dotazován prostřednictvím GetRequiredService.

Přepsání služeb

Kromě vložení nových služeb je možné pomocí této techniky také přepsat dříve injektované služby na stránce. Následující obrázek znázorňuje všechna pole dostupná na stránce použité v prvním příkladu:

Kontextová nabídka IntelliSense pro zadaná pole symbolu @ se seznamem polí Html, Component, StatsService a Url

Jak vidíte, výchozí pole zahrnují , a (a také pole , Html Component které jsme Url StatsService vloženého souboru). Pokud byste například chtěli nahradit výchozí pomocníky HTML vlastními, mohli byste to snadno udělat pomocí @inject příkazu :

@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>

Pokud chcete rozšířit stávající služby, můžete tuto techniku jednoduše použít při dědění nebo zabalení existující implementace s vlastní.

Viz také