ASP.NET Core BlazorアプリケーションでのDIコンテナを利用するコードを紹介します。
ASP.NET Core BlazorアプリケーションでDIコンテナを利用するコードを紹介します。
ASP.NET Core Webアプリケーションのプロジェクトを作成します。手順はこちらの記事を参照して下さい。
サービスクラスのコード MyService.cs を追加します。コードは下記です。
MyServiceクラスを実装します。MyServiceクラスはExecメソッドを1つ持つクラスです。また、MyServiceクラスの基底のインターフェイス IMyService も実装します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DIContainer
{
public interface IMyService
{
public string Exec();
}
public class MyService : IMyService
{
public string Exec()
{
return "Hello! Blazor App DI Container World!";
}
}
}
App.razor, _Imports.razor, Startup.cs のコードを編集します。
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" />
</Found>
<NotFound>
<LayoutView>
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
@using System.Net.Http
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
Startup.csではConfigureServices() メソッドで services.AddSingleton メソッドを呼び出し先に実装した MyServiceクラスをDIコンテナに追加します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace DIContainer
{
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 https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMyService, MyService>();
services.AddRazorPages();
services.AddServerSideBlazor();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
フォールバックページを追加します。
@page
@namespace DIContainer.Pages
<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<app>
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</app>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
画面のrazorコンポーネントを追加します。今回の例では、Screen.razor ファイルとScreen.razorのモデルクラスを実装するScreen.razor.csファイルを追加します。コードは以下です。
@page "/Screen"
@inherits ScreenModel
<h3>Index</h3>
<button @onclick="ButtonClick">Button1</button>
<p>@MessageText</p>
@code {
}
ScreenModelクラスは、ComponentBaseの派生クラスとして実装します。razorコンポーネントのコードビハインドについてはこちらの記事を参照して下さい。
DIコンテナに登録されたIMyService オブジェクトを参照する場合はクラスの記述で、Inject属性を利用してサービスのプロパティを宣言します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
namespace DIContainer.Pages
{
public class ScreenModel:ComponentBase
{
[Inject]
public IMyService mysevice { get; set; }
public string MessageText;
public void ButtonClick()
{
MessageText = mysevice.Exec();
}
}
}
プロジェクトを実行します。Webブラウザが起動しますので (アプリケーションルートURL)/Screen
のURLにアクセスします。下図のページが表示されます。画面の[Button1]をクリックします。
画面のボタンの下に "Hello! Blazor App DI Container World!" の文字列が表示されます。DIコンテナからInject属性を設定した myservice変数にインスタンスが実行でき正しく値を返す動作になっていることが確認できます。
先の例では、razorコンポーネントのページに対するモデルクラスがある場合のコードを紹介しました。Blazorアプリケーションではrazorコンポーネントのページに対してモデルクラスが無い場合や、razorコンポーネント内の@code
セクションのコードからインジェクションしたオブジェクトを参照したいこともあります。
razorコンポーネントページでオブジェクトをインジェクトして参照する場合は、razorコンポーネントのページに @Inject
ディレクティブを記述します。
razorコンポーネントを追加しページを作成します。
@page "/ScreenLight"
@inject IMyService ms
<h3>ScreenLight</h3>
<button @onclick="Button2Click">Button2</button>
<p>@messageText</p>
@code {
string messageText;
void Button2Click()
{
messageText = ms.Exec();
}
}
ScreenLight.razor
は Screen.razor
と同じ動作をするページです。Screen.razorはモデルクラスが別ファイルで存在します。一方 ScreenLight.razor
はボタンクリック後のロジックもrazorファイル中に実装しています。そのため、razorファイル内に、MyServiceオブジェクトをインジェクトして参照する必要があります。
razorファイルで下記の@inject
ディレクティブによりオブジェクトをインジェクトしてrazorファイル中で参照できます。ms
がインスタンス化されたオブジェクトになります。
@inject IMyService ms
ms.Exec()
の記述により、MyServiceクラスの Exec メソッドが呼び出され、文字列を返します。返された文字列を画面に表示します。
void Button2Click()
{
messageText = ms.Exec();
}
プロジェクトを実行します。(アプリケーションルートURL)/ScreenLight
にWebブラウザでアクセスします。下図のページが表示されます。
ページの[Button2]をクリックします。MyServiceクラスのExecメソッドが呼び出され、戻り値の文字列がページに表示されます。
インジェクションするサービスが複数の場合です。上記のコードに YourService.cs クラスを追加します。
コードは以下です。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace DIContainer
{
public interface IYourService
{
public string Exec();
}
public class YourService : IYourService
{
public string Exec()
{
return "DIコンテナの世界にようこそ。";
}
}
}
Startup.cs にYourServiceクラスをDIコンテナに追加するコードを記述します。
Configureメソッドにservices.AddSingleton<IYourService, YourService>();
を追記し下記の通り変更します。
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMyService, MyService>();
services.AddSingleton<IYourService, YourService>();
services.AddRazorPages();
services.AddServerSideBlazor();
}
Blazorアプリケーションの画面(ページ)を追加します。ScreenMulti.razor の名称でrazorコンポーネントを追加します。
ScreenMulti.razor では @page "/ScreenMulti"
により、(アプリケーションルートURL)/ScreenMulti
にアクセスした際にこの画面を表示します。@inject ディレクティブにより、IMyService, IYourService の2つのオブジェクトをインジェクトして参照できる状態にしています。ボタンクリック時の処理では、IMyServiceのExecメソッドと、IYourService のExecメソッドを呼び出し、2つの結果を結合して画面に表示しています。
@page "/ScreenMulti"
@inject IMyService ms
@inject IYourService ys
<h3>ScreenMulti</h3>
<button @onclick="Button3Click">Button3</button>
<p>@messageText</p>
@code {
string messageText;
void Button3Click()
{
messageText = ms.Exec() +" : "+ ys.Exec();
}
}
プロジェクトを実行します。Webブラウザで (アプリケーションルートURL)/ScreenMulti
のURLにアクセスします。下図の画面が表示されます。
[Button3]をクリックします。画面に"Hello! Blazor App DI Container World! : DIコンテナの世界にようこそ。" のメッセージが表示され、MyServiceクラスのExecメソッドの戻り値と、YourServiceクラスのExecメソッドの戻り値との両方の値が画面に表示されます。
IWebHostEnvironment をインジェクションするコードを紹介します。
先のコードでは自分で実装したクラスをインジェクションして利用しましたが、ASP.NET Core のフレームワークでインジェクションできるフレームワークが提供するサービスがあります。IWebHostEnvironment はフレームワークが提供するサービスの一つでアプリケーション名やアプリケーションの配置パスなどの環境情報を参照できるサービスです。このサービスをインジェクションしてページモデルなどで利用するコードを紹介します。
上記のプログラムに OurService.cs ファイルを追加します。下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
namespace DIContainer
{
public interface IOurService
{
public string Exec();
}
public class OurService:IOurService
{
IWebHostEnvironment _env;
IMyService _ms;
IYourService _ys;
public OurService(IWebHostEnvironment env, IMyService ms, IYourService ys)
{
_env = env;
_ms = ms;
_ys = ys;
}
public string Exec()
{
return _ms.Exec() + " : " + _ys.Exec() + " : " + _env.ApplicationName;
}
}
}
Startup.csファイルのConfigureメソッドを変更し、先に作成した OurService クラスをDIコンテナに追加します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace DIContainer
{
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 https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMyService, MyService>();
services.AddSingleton<IYourService, YourService>();
services.AddSingleton<IOurService, OurService>();
services.AddRazorPages();
services.AddServerSideBlazor();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
画面を追加します。
@page "/ScreenEnv"
により、アプリケーションルートURL下の ScreenEnv ディレクトリアクセス時に画面を表示します。画面内のボタンをクリックした際には、インジェクションにより参照される、OurServiceクラスの Exec()
メソッドを呼び出します。
@page "/ScreenEnv"
@inject IOurService os
<h3>ScreenEnviroment</h3>
<button @onclick="Button3Click">Button3</button>
<p>@messageText</p>
@code {
string messageText;
void Button3Click()
{
messageText = os.Exec();
}
}
/ScreenEnv 画面のButton3クリックにより、OurServiceクラスのExecメソッドが呼び出されます。
OurServiceのコンストラクタでは、IWebHostEnvironment, IMyService, IYourService の3つのパラメーターをとります。コンストラクタで受け取ったオブジェクトはメンバ変数の_env, _ms, _ys に代入して保持します。
Exec()
メソッドが呼び出された時点で、WebHostEnvironmentクラスのApplicationName
, MyServiceクラスのExec()
メソッド, YourServiceクラスのExec()
メソッドを呼び出し、それぞれの戻り値の文字列を連結して画面に表示します。
public class OurService:IOurService
{
IWebHostEnvironment _env;
IMyService _ms;
IYourService _ys;
public OurService(IWebHostEnvironment env, IMyService ms, IYourService ys)
{
_env = env;
_ms = ms;
_ys = ys;
}
public string Exec()
{
return _ms.Exec() + " : " + _ys.Exec() + " : " + _env.ApplicationName;
}
}
プロジェクトを実行し、Webブラウザで (アプリケーションルートURL)/ScreenMulti
のURLにアクセスします。下図の画面が表示されます。
[Button3]をクリックします。OurServiceクラスのExecメソッドが呼び出されメソッドの戻り値が画面に表示されます。
DIコンテナやインジェクションのメリットとしては次のものがあります。
ASP.NET Coreではフレームワークが提供するサービスオブジェクトがあります。必要となるサービスオブジェクトを@inject
ディレクティブやInjet属性、コンストラクタインジェクションで簡単に追加できます。
DIコンテナに登録すれば、コンストラクタに参照したいオブジェクトを追加するだけで簡単にオブジェクトの参照を追加できます。
DIを利用したコードでは、インスタンス化されたオブジェクトがコンストラクタの引数で渡されます。そのため、参照元のクラスでインスタンスを作成する必要が無いため、参照先のクラスの参照も不要になります。
クラスのインスタンスをクラス型の変数に格納すると、クラスへの参照が必要になりますが、DIでは参照先のクラスの基底のインターフェイス型の変数を利用してインスタンスオブジェクトを格納します。このため、メソッドの呼び出しなどにおいてもクラスの参照が不要になります。