2019年6月14日 星期五

ASP.NET Core 下使用 Unity DI 容器做到屬性注入功能

ASP.NET Core 下使用 Unity DI 容器 Container 做到屬性注入功能

當在進行 ASP.NET Core 專案開發的時候,就會預設有提供一個 DI 容器,也就是 Microsoft.Extensions.DependencyInjection 這個套件,不過,這個套件說實在的功能上有些陽春,不過對於基本的相依性注入上的需求,已經相當的充分足夠了;若想要使用使用這個套件做到 屬性注入 Property Injection 這樣的功能(雖然屬性注入的功能並不建議使用這樣的功能),在 Microsoft.Extensions.DependencyInjection 套件下,是不提供這樣的機制;若想要使用更多的 DI 容器功能,這個時候要設定在 ASP.NET Core 專案內可以使用其他的 DI 容器,接著要設定當要產生控制器物件的時候,使用 Unity 相依性注入容器來做為產生與注入該控制器物件的來源。
這篇文章的專案範例原始碼可以從 GitHub 取得
請先建立一個 ASP.NET Core Web API 的專案
接著,請在這個專案內來安裝 Unity.Microsoft.DependencyInjection 這個 Unity DI 容器套件,以便可以在 ASP.NET Core 專案內使用 Unity 相依性注入的容器功能
現在,可以打開 Program.cs 這個檔案,在這個 public static IWebHostBuilder CreateWebHostBuilder(string[] args) 方法內,加入這個 .UseUnityServiceProvider() 方法呼叫 ,對 ASP.NET Core 專案來註冊 Unity DI Container 這個類別庫軟體。
C Sharp / C#
public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseUnityServiceProvider()
            .UseStartup<Startup>();
}
現在打開 [Startup.cs] 這個檔案,在這個檔案內增加一個 IMessage 介面,與兩個實作 IMessage 這個介面的類別,分別是 ConsoleMessage, FileMessage。
C Sharp / C#
public interface IMessage
{
    string Send(string message);
}

public class ConsoleMessage : IMessage
{
    public string Send(string message)
    {
        string result = $"ConsoleMessage :{message}";
        Console.WriteLine(result);
        return result;
    }
}
public class FileMessage : IMessage
{
    public string Send(string message)
    {
        string result = $"FileMessage :{message}";
        Console.WriteLine(result);
        return result;
    }
}
請在 Startup 類別內,加入這個方法 ConfigureContainer ,這裡將會進行整個 DI 容器的抽象型別與具體實作類別的關係註冊,其方法將會傳入一個 IUnityContainer 型別參數,因此,在這裡將會這個參數 container 物件,使用 Unity DI Container 的語法,進行這些型別關係的註冊。
C Sharp / C#
public void ConfigureContainer(IUnityContainer container)
{
    // Could be used to register more types
    container.RegisterType<IMessage, ConsoleMessage>();
}
接著,打開 Controllers 資料夾下的 ValuesController.cs 這個檔案,在這個類別 ValuesController ,將會建立一個建構函式,這個函式將會接收一個 IMessage 參數,這個參數將會於這個控制器被建立的時候,將會注入到這個建構函式內。
另外,將會宣告一個 IMessage 型別的屬性 messageProperty,不過,在這裡將會想要使用 屬性注入的功能,當這個類別被產生的時候,將會透過 DI 容器來注入到這個屬性內;這裡將會使用 [Dependency] 標示在這個屬性上,這是 Unity DI 容器的使用宣告方式。
在 Get 動作內,請在 return 敘述上設定一個中斷點,現在開始執行這個專案,此時,程式將會停留在這個中斷點上;請將游標移動到 this.message 這個欄位上,就會看到如下圖的畫面,透過建構函式的注入方式,取得到一個 IMessage 的服務物件,該服務物件為 ConsoleMessage 的型別。
現在,請將游標移動到 meesageProperty 這個屬性上,雖然這個屬性有標示 Dependency 這個 Attribute,不過,且看到 DI 容器卻沒有使用 Unity 的屬性注入用法,使用屬性注入的方式將依個服務物件注入到該屬性上。
C Sharp / C#
public class ValuesController : ControllerBase
{
    private readonly IMessage message;
    [Dependency]
    public IMessage messageProperty { get; set; }

    public ValuesController(IMessage message)
    {
        this.message = message;
    }
    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "value1", "value2", message.Send("Vulcan") };
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return "value";
    }

    // POST api/values
    [HttpPost]
    public void Post([FromBody] string value)
    {
    }

    // PUT api/values/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody] string value)
    {
    }

    // DELETE api/values/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
}
現在,請打開 Startup.cs 檔案,在 Startup 類別內找到 ConfigureServices 方法,在 AddMvc() 方法內加入這個方法呼叫 .AddControllersAsServices(),因為預設 ASP 解析控制器將會使用內建的啟用器,所以使用這個方法呼叫,將會當要進行控制器型別解析的時候,可以使用 Unity 容器作為相依性注入的來源。
接著,請再度執行這個專案,此時將會停留在之前設定的中斷點,現在,將游標移動到 messageProperty 上,現在就會看到如下圖,這個屬性已經自動注入了服務物件。
C Sharp / C#
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
        .AddControllersAsServices();
}








沒有留言:

張貼留言