ASP.NET Core でのビューへの依存関係の挿入Dependency injection into views in ASP.NET Core

作成者: Steve SmithBy Steve Smith

ASP.NET Core では、ビューへの依存関係の挿入をサポートしています。ASP.NET Core supports dependency injection into views. この機能は、ビュー要素を作成するためだけに必要なローカライズやデータなど、ビュー固有のサービスに役立ちます。This can be useful for view-specific services, such as localization or data required only for populating view elements. コントローラーとビューの間で関心の分離を保持する必要があります。You should try to maintain separation of concerns between your controllers and views. ビューに表示されるデータのほとんどは、コントローラーから渡されます。Most of the data your views display should be passed in from the controller.

サンプル コードを表示またはダウンロードします (ダウンロード方法)。View or download sample code (how to download)

構成の挿入Configuration injection

appsettings.json 値は、ビューに直接挿入できます。appsettings.json values can be injected directly into a view.

appsettings.json ファイルの例:Example of an appsettings.json file:

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

@inject: @inject <type> <name> の構文The syntax for @inject: @inject <type> <name>

@inject を使用した例:An example using @inject:

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

サービスの挿入Service injection

@inject ディレクティブを使用して、サービスをビューに挿入することができます。A service can be injected into a view using the @inject directive. @inject は、ビューにプロパティを追加したり、DI を使用してプロパティを設定したりするものと考えることができます。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>

このビューでは、全体的な統計を示す概要と共に、ToDoItem インスタンスのリストが表示されます。This view displays a list of ToDoItem instances, along with a summary showing overall statistics. 概要は、挿入された StatisticsService から作成されます。The summary is populated from the injected StatisticsService. このサービスは、Startup.cs 内の ConfigureServices の依存関係の挿入に登録されます。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 では、ToDoItem インスタンスのセットでいくつかの計算を実行します。これには、次のリポジトリを使用してアクセスします。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);
        }
    }
}

サンプルのリポジトリでは、メモリ内のコレクションを使用します。The sample repository uses an in-memory collection. 上記の (メモリ内のすべてのデータを操作する) 実装は、大規模なリモートでアクセスされるデータ セットにはお勧めしません。The implementation shown above (which operates on all of the data in memory) isn't recommended for large, remotely accessed data sets.

サンプルには、ビューとビューに挿入されたサービスにバインドされたモデルからのデータが表示されています。The sample displays data from the model bound to the view and the service injected into the view:

合計項目数、完了した項目数、優先度の平均、および優先度と完了を示すブール値を含むタスクのリストを一覧する To Do ビュー。

ルックアップ データの作成Populating Lookup Data

ビューの挿入は、ドロップダウン リストなど、UI 要素のオプションの作成に役立ちます。View injection can be useful to populate options in UI elements, such as dropdown lists. 性別、状態、およびその他の基本設定を指定するオプションを含む、ユーザー プロファイル フォームを検討します。Consider a user profile form that includes options for specifying gender, state, and other preferences. 標準の MVC アプローチを使用するフォームのようなレンダリングには、これらのオプションのセットごとにデータ アクセス サービスを要求し、バインドするオプションの各セットを含むモデルまたは ViewBag を作成するために、コントローラーが必要です。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.

別のアプローチでは、オプションを取得するために、ビューに直接サービスを挿入します。An alternative approach injects services directly into the view to obtain the options. これにより、このビュー要素の構築ロジックをビュー自体に移動して、コントローラーから要求されるコードの量を最小限にします。This minimizes the amount of code required by the controller, moving this view element construction logic into the view itself. プロファイルの編集フォームを表示するコントローラー アクションは、フォームにプロファイル インスタンスを渡すためにのみ必要です。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);
        }
    }
}

これらの基本設定を更新するために使用される HTML フォームには、3 つのプロパティのドロップダウン リストが含まれます。The HTML form used to update these preferences includes dropdown lists for three of the properties:

名前、性別、状態、好きな色の入力を許可するフォームを含む、[Update Profile] (プロファイルの更新) ビュー。

これらのリストは、ビューに挿入されたサービスによって作成されます。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 は、このフォームに必要なデータだけを提供する UI レベルのサービスです。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" };
        }
    }
}

重要

Startup.ConfigureServices での依存関係の挿入を介して要求する型を登録するのを忘れないでください。Don't forget to register types you request through dependency injection in Startup.ConfigureServices. サービス プロバイダーは GetRequiredService を介して内部的にクエリが実行されるため、未登録の型は実行時に例外をスローします。An unregistered type throws an exception at runtime because the service provider is internally queried via GetRequiredService.

サービスのオーバーライドOverriding Services

新しいサービスを挿入するだけでなく、この技術はページ上の以前に挿入されたサービスをオーバーライドするためにも使用できます。In addition to injecting new services, this technique can also be used to override previously injected services on a page. 以下の図は、最初の例で使用されたページで利用できるすべてのフィールドを示しています。The figure below shows all of the fields available on the page used in the first example:

@ 記号を入力して、Html、Component、StatsService、Url フィールドが一覧された IntelliSense コンテキスト メニュー

ご覧のように、既定のフィールドには、HtmlComponentUrl (さらに、挿入した StatsService) が含まれます。As you can see, the default fields include Html, Component, and Url (as well as the StatsService that we injected). たとえば、既定の HTML ヘルパーを自分のヘルパーに置き換える場合は、@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>

既存のサービスを拡張する場合、独自に既存の実装から継承したり、ラップしたりするときに、この技術を使用できます。If you want to extend existing services, you can simply use this technique while inheriting from or wrapping the existing implementation with your own.

関連項目See Also