Dela via


Beroendeinmatning i vyer i ASP.NET Core

ASP.NET Core stöder beroendeinmatning i vyer. Detta kan vara användbart för visningsspecifika tjänster, till exempel lokalisering eller data som endast krävs för att fylla i vyelement. De flesta datavyer som visas ska skickas in från kontrollanten.

Visa eller ladda ned exempelkod (hur du laddar ned)

Konfigurationsinjektion

Värdena i inställningsfiler, till exempel appsettings.json och appsettings.Development.json, kan matas in i en vy. Överväg appsettings.Development.json från exempelkod:

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

Följande markering visar konfigurationsvärdet i vyn Razor Pages:

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

Följande markering visar konfigurationsvärdet i en MVC-vy:

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

Mer information finns i Configuration i ASP.NET Core

Tjänsteinjektion

En tjänst kan matas in i en vy med hjälp av @inject-direktivet.

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

Den här vyn visar en lista över ToDoItem instanser, tillsammans med en sammanfattning som visar övergripande statistik. Sammanfattningen fylls i från den inmatade StatisticsService. Den här tjänsten är registrerad för beroendeinmatning i ConfigureServices i 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 utför vissa beräkningar på uppsättningen ToDoItem instanser som den kommer åt via en lagringsplats:

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

Exempeldatabasen använder en minnesintern samling. En minnesintern implementering bör inte användas för stora, fjärranslutna datauppsättningar.

Exemplet visar data från modellen som är bunden till vyn och tjänsten som matas in i vyn:

Att göra-vyn som visar totalt antal objekt, slutförda objekt, genomsnittlig prioritet och en lista över aktiviteter med deras prioritetsnivåer och booleska värden som anger slutförande.

Fylla i uppslagsdata

Vyinsprutning kan vara användbart för att fylla i val i lister över användargränssnittselement, till exempel rullgardinsmenyer. Överväg ett användarprofilformulär som innehåller alternativ för att ange kön, tillstånd och andra inställningar. Återgivning av ett sådant formulär med en standardmetod kan kräva att kontrollanten eller Razor-sidan:

  • Begär dataåtkomsttjänster för var och en av alternativen.
  • Fyll i en modell eller ViewBag med varje uppsättning alternativ som ska bindas.

En alternativ metod matar in tjänster direkt i vyn för att få alternativen. Detta minimerar mängden kod som krävs av kontrollen eller Razor-sidan och flyttar denna logik för konstruktion av visningselement till själva vyn. Kontrollantåtgärden eller Razor sidan för att visa ett profilredigeringsformulär behöver bara skicka formuläret till profilinstansen:

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

HTML-formuläret som används för att uppdatera inställningarna innehåller listrutor för tre av egenskaperna:

Uppdatera profilvyn med ett formulär som tillåter inmatning av namn, kön, tillstånd och favoritfärg.

De här listorna fylls i av en tjänst som har integrerats med vyn.

@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 är en tjänst på användargränssnittsnivå som är utformad för att bara tillhandahålla de data som behövs för det här formuläret:

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

Observera att en oregistrerad typ utlöser ett undantag vid körning eftersom tjänstleverantören frågas internt via GetRequiredService.

Åsidosättande tjänster

Förutom att mata in nya tjänster kan den här tekniken användas för att åsidosätta tidigare inmatade tjänster på en sida. Bilden nedan visar alla fält som är tillgängliga på sidan som används i det första exemplet:

Intellisense-snabbmenyn på den skrivna @-symbolen med HTML-, komponent-, StatsService- och URL-fält

Standardfälten innehåller Html, Componentoch Url. Om du vill ersätta HTML-standardhjälparna med en anpassad version använder du @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>

Se även

ASP.NET Core stöder beroendeinmatning i vyer. Detta kan vara användbart för visningsspecifika tjänster, till exempel lokalisering eller data som endast krävs för att fylla i vyelement. Du bör försöka upprätthålla separation av ansvar mellan dina kontroller och vyer. De flesta av de data som dina vyer visar bör skickas in från kontrollern.

Visa eller ladda ned exempelkod (hur du laddar ned)

Konfigurationsinjektion

appsettings.json-värden kan injiceras direkt i en vy.

Exempel på en appsettings.json fil:

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

Syntaxen för @inject: @inject <type> <name>

Ett exempel med @inject:

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

Serviceinjektion

En tjänst kan matas in i en vy med hjälp av @inject-direktivet. Du kan tänka dig @inject som att lägga till en egenskap i vyn och fylla i egenskapen med 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>

Den här vyn visar en lista över ToDoItem instanser, tillsammans med en sammanfattning som visar övergripande statistik. Sammanfattningen fylls i från den inmatade StatisticsService. Den här tjänsten är registrerad för beroendeinjicering i ConfigureServices i 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 utför vissa beräkningar på uppsättningen ToDoItem instanser som den kommer åt via en lagringsplats:

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

Exempellagringsplatsen använder en minnesintern samling. Implementeringen som visas ovan (som fungerar på alla data i minnet) rekommenderas inte för stora, fjärranslutna datauppsättningar.

Exemplet visar data från modellen som är bunden till vyn och tjänsten som matas in i vyn:

Att göra-vyn som visar totalt antal objekt, slutförda objekt, genomsnittlig prioritet och en lista över aktiviteter med deras prioritetsnivåer och booleska värden som anger slutförande.

Fylla i uppslagsdata

Vyinjektion kan vara användbart för att fylla i alternativ i gränssnittselement, till exempel listrutor. Överväg ett användarprofilformulär som innehåller alternativ för att ange kön, tillstånd och andra inställningar. Om ett sådant formulär återges med en standardmetod för MVC skulle kontrollanten begära dataåtkomsttjänster för var och en av dessa uppsättningar alternativ och sedan fylla i en modell eller ViewBag med varje uppsättning alternativ som ska bindas.

En alternativ metod matar in tjänster direkt i vyn för att få alternativen. Detta minimerar mängden kod som krävs av kontrollanten och flyttar den här vyns elementkonstruktionslogik till själva vyn. Kontrollantåtgärden för att visa ett profilredigeringsformulär behöver bara skicka formuläret till profilinstansen:

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

HTML-formuläret som används för att uppdatera dessa inställningar innehåller listrutor för tre av egenskaperna:

Uppdatera profilvyn med ett formulär som tillåter inmatning av namn, kön, tillstånd och favoritfärg.

De här listorna fylls i av en tjänst som har infogats i vyn.

@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 är en tjänst på användargränssnittsnivå som är utformad för att bara tillhandahålla de data som behövs för det här formuläret:

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

Viktig

Glöm inte att registrera typer du begär via beroendeinjektion i Startup.ConfigureServices. En oregistrerad typ utlöser ett undantag vid körning eftersom tjänstleverantören förfrågas internt via GetRequiredService.

Åsidosättande tjänster

Förutom att mata in nya tjänster kan den här tekniken också användas för att åsidosätta tidigare inmatade tjänster på en sida. Bilden nedan visar alla fält som är tillgängliga på sidan som används i det första exemplet:

Intellisense-snabbmenyn på en typad @-symbol med HTML-, Komponent-, StatsService- och URL-fält

Som du ser innehåller standardfälten Html, Componentoch Url (samt de StatsService som vi har matat in). Om du till exempel vill ersätta HTML-standardhjälparna med dina egna kan du enkelt göra det med hjälp av @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>

Om du vill utöka befintliga tjänster kan du helt enkelt använda den här tekniken när du ärver från eller omsluter den befintliga implementeringen med din egen.

Se även