読者です 読者をやめる 読者になる 読者になる

ASP.NET Core MVC のDIコンテナを利用する Part.0(準備編)

Dependency Injection(DI)は有益だという前提で話をします

「SOLID原則」などに代表されるオブジェクト指向設計のパターンや原則は、「まあ、大事だよねえ」と思いつつも、「そうは言っても今一つピンと来ないなあ」と思ったりすることもあったりします。
ですので、今日はDIコンテナの話を書くのですが、「なぜ有益か」という話はあまり深入りしないようにしようと思います。

DIは結合度を減らす

例えば、下記のようなコードを考えます。

public class NiceController : Controller
{
  public static string Name { get; } = "Nice";

  private readonly ValueService _service;

  public NiceController()
  {
    _service = new ValueService();
  }
      
  public IActionResult Index()
  {
    ViewData["value"] = _service.GetValue();
    return View();
  }
}
// Services\ValueService.cs
public class ValueService
{
  public int GetValue()
  {
    return this.GetHashCode();
  }
}

このコードは、コントローラーのコンストラクタでサービスであるValueServiceインスタンスを生成し、Indexアクションにてそれを利用しています。
こういうコードはよくありがちですが、コントローラーとサービスのクラスが強く「結合」しており、一般的によろしくないとされています。
この場合のサービスValueServiceを「依存しているオブジェクト」("dependency")と呼びます。

では次にこういう結合を弱めるためにできることとして、外部からインスタンスを与えます。

private readonly ValueService _service;

public NiceController(ValueService service)
{
  _service = service;
}

上記のようにコンストラクタに対して、インスタンスを外部から与えることができれば、コントローラー側はサービスValueServiceのインスタンス生成について考慮する必要がなくなります。
さらにいうとコントローラーはサービスの処分についても考慮する必要がなくなるでしょう。

上記のように外部から依存しているオブジェクトを与えることがDependency Injection(DI)パターンと呼ばれるものです。

さらに一歩進める

上記でDIは一応成り立っているのですが、さらに一歩前進して、下記のように抽象化します。

private readonly IValueService _service;

public NiceController(IValueService service)
{
  _service = service;
}
// Services\IValueService.cs
public interface IValueService
{
  int GetValue();
}
// Services\ValueService.cs
public class ValueService : IValueService
{
  public int GetValue()
  {
    return this.GetHashCode();
  }
}

上記により、コントローラー側はサービスの実装(ValueService)との結合がなくなり、IValueService*1を実装したサービスであれば受け取れるようになりました。
これにより、

などのメリットがあります。

それでは、どうやってコントローラーのコンストラクタに ValueService(=ValueService) を渡すのでしょうか。
そのための仕組みがDIコンテナです。
ASP.NET Core MVCでは組み込みのDIコンテナが実装され、簡単に使うことができます。

その解説は次回にします。

おすすめリンク

やはりあなた方のDependency Injectionはまちがっている。 — A Day in Serenity (Reloaded) — PHP, FuelPHP, Linux or something

*1:Interfaceの抽出はVisualStudioの右クリックメニュー[Quick Actions and Refactorings...]を使うと便利です