Inserimento di dipendenze nelle visualizzazioni in ASP.NET CoreDependency injection into views in ASP.NET Core

Di Steve SmithBy Steve Smith

ASP.NET Core supporta l'inserimento di dipendenze nelle visualizzazioni.ASP.NET Core supports dependency injection into views. Questo può essere utile per i servizi specifici delle visualizzazioni, ad esempio per la localizzazione o per dati necessari solo per il popolamento degli elementi delle visualizzazioni.This can be useful for view-specific services, such as localization or data required only for populating view elements. È consigliabile mantenere la separazione delle competenze tra i controller e le visualizzazioni.You should try to maintain separation of concerns between your controllers and views. La maggior parte dei dati nelle visualizzazioni devono essere passati dal controller.Most of the data your views display should be passed in from the controller.

Visualizzare o scaricare il codice di esempio (procedura per il download)View or download sample code (how to download)

Inserimento della configurazioneConfiguration injection

I valori di appsettings.json possono essere inseriti direttamente in una visualizzazione.appsettings.json values can be injected directly into a view.

Esempio di un file appsettings.json:Example of an appsettings.json file:

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

Sintassi per @inject: @inject <type> <name>The syntax for @inject: @inject <type> <name>

Esempio che usa @inject:An example using @inject:

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

Inserimento del servizioService injection

È possibile inserire un servizio in una visualizzazione usando la direttiva @inject.A service can be injected into a view using the @inject directive. È possibile considerare @inject l'aggiunta di una proprietà alla visualizzazione, con il popolamento della proprietà tramite inserimento delle dipendenze.You can think of @inject as adding a property to the view, and populating the property using 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>

Questa visualizzazione presenta un elenco di istanze di ToDoItem, nonché un riepilogo con statistiche generali.This view displays a list of ToDoItem instances, along with a summary showing overall statistics. Il riepilogo è popolato dal servizio StatisticsService inserito.The summary is populated from the injected StatisticsService. Questo servizio è registrato per l'inserimento di dipendenze in ConfigureServices in Startup.cs:This service is registered for dependency injection in ConfigureServices in 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>();

StatisticsService esegue alcuni calcoli per il set di istanze di ToDoItem, a cui accede tramite un repository:The StatisticsService performs some calculations on the set of ToDoItem instances, which it accesses via a repository:

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

Il repository di esempio usa una raccolta in memoria.The sample repository uses an in-memory collection. L'implementazione illustrata in precedenza, che opera su tutti i dati in memoria, non è consigliata per set di dati di grandi dimensioni a cui si accede in remoto.The implementation shown above (which operates on all of the data in memory) isn't recommended for large, remotely accessed data sets.

L'esempio visualizza i dati del modello associato alla visualizzazione e il servizio inserito nella visualizzazione stessa:The sample displays data from the model bound to the view and the service injected into the view:

Visualizzazione To Do con l'elenco degli elementi totali, degli elementi completati e della priorità media, e con un elenco di attività con i relativi livelli di priorità e i valori booleani che indicano il completamento.

Popolamento di dati di ricercaPopulating Lookup Data

L'inserimento di visualizzazioni può essere utile per popolare le opzioni negli elementi dell'interfaccia utente, ad esempio negli elenchi a discesa.View injection can be useful to populate options in UI elements, such as dropdown lists. Si consideri un modulo di profilo utente che include opzioni che consentono di specificare il sesso, lo stato e altre preferenze.Consider a user profile form that includes options for specifying gender, state, and other preferences. Per il rendering di un form di questo tipo tramite un approccio MVC standard sarebbe necessario che il controller richiedesse servizi di accesso ai dati per ognuno di questi set di opzioni e quindi popolasse un modello o un ViewBag con ogni set di opzioni da associare.Rendering such a form using a standard MVC approach would require the controller to request data access services for each of these sets of options, and then populate a model or ViewBag with each set of options to be bound.

Un approccio alternativo consiste nell'ottenere le opzioni inserendo i servizi direttamente nella visualizzazione.An alternative approach injects services directly into the view to obtain the options. In questo modo la quantità di codice necessario per il controller viene ridotta al minimo, dato che la logica di costruzione di questo elemento di visualizzazione viene spostata nella visualizzazione stessa.This minimizes the amount of code required by the controller, moving this view element construction logic into the view itself. L'azione del controller per la visualizzazione di un modulo di modifica del profilo deve solo passare l'istanza del profilo al modulo:The controller action to display a profile editing form only needs to pass the form the profile instance:

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

Il form HTML usato per aggiornare queste preferenze include elenchi a discesa per tre delle proprietà:The HTML form used to update these preferences includes dropdown lists for three of the properties:

Visualizzazione Update Profile con un modulo che consente l'immissione di nome, sesso, stato e colore preferito.

Questi elenchi vengono popolati da un servizio inserito nella visualizzazione:These lists are populated by a service that has been injected into the view:

@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 è un servizio a livello di interfaccia utente progettato per fornire solo i dati necessari per il modulo:The ProfileOptionsService is a UI-level service designed to provide just the data needed for this form:

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

Importante

Non si deve dimenticare di registrare i tipi che si richiedono tramite l'inserimento di dipendenze nel metodo Startup.ConfigureServices.Don't forget to register types you request through dependency injection in Startup.ConfigureServices. Un tipo non registrato genera un'eccezione in fase di runtime, perché viene eseguita internamente una query al provider di servizi tramite GetRequiredService.An unregistered type throws an exception at runtime because the service provider is internally queried via GetRequiredService.

Override di serviziOverriding Services

Oltre all'inserimento di nuovi servizi, questa tecnica può essere usata anche per eseguire l'override di servizi precedentemente inseriti in una pagina.In addition to injecting new services, this technique can also be used to override previously injected services on a page. La figura seguente mostra tutti i campi disponibili nella pagina usata nel primo esempio:The figure below shows all of the fields available on the page used in the first example:

Menu di scelta rapida di IntelliSense in un simbolo @ tipizzato con l'elenco dei campi Html, Component, StatsService e Url

Come si può notare, i campi predefiniti includono Html, Component, e Url, nonché il servizio StatsService inserito.As you can see, the default fields include Html, Component, and Url (as well as the StatsService that we injected). Se ad esempio si vogliono sostituire gli helper HTML predefiniti con helper personalizzati, è possibile farlo facilmente tramite @inject:If for instance you wanted to replace the default HTML Helpers with your own, you could easily do so using @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 si vuole estendere i servizi esistenti, è sufficiente usare questa tecnica mentre si eredita dall'implementazione esistente o si esegue il wrapping di quest'ultima con un'implementazione personalizzata.If you want to extend existing services, you can simply use this technique while inheriting from or wrapping the existing implementation with your own.

Vedere ancheSee Also