[翻譯] Autofac 入門文檔


原文鏈接:http://docs.autofac.org/en/latest/getting-started/index.html

在程序中使用Autofac的基本模式是:

  • 用控制反轉(IoC)的思想組織程序。
  • 添加對 Autofac 的引用。
  • 程序啟動階段
    • 創建 ContainerBuilder
    • 注冊組件。
    • 生成容器。
  • 程序執行階段
    • 從容器創建生命周期范圍對象(ILifetimeScope接口)。
    • 使用生命周期范圍對象解析組件實例。

本文通過一個簡單的控制台程序演示這些步驟。

組織程序

控制反轉的基本思路是,不讓類創建它的依賴項,而是將依賴項通過構造函數傳遞給它。請參閱 Martin Fowler 這篇解釋依賴注入/控制反轉的文章。中文翻譯

在本示例中,我們定義一個輸出“今天”的日期的類。但是,我們不想讓它和 Console 類捆綁在一起。這有兩個原因:1,方便測試,2,在沒有Console的環境中也能使用。

我們還對輸出日期的方式進行抽象,這樣就可以隨時切換到另一個版本,比如輸出“明天”的日期。

代碼:

using System;

namespace DemoApp
{

  // 此接口將“輸出”概念從Console類解耦。
  // 我們只管“輸出”,而不關心操作是怎么進行的。
  public interface IOutput
  {
    void Write(string content);
  }
 
  // 這里的實現方式是向Console輸出內容。
  // 也可以用其他方式,比如輸出到 Debug 和 Trace。
  public class ConsoleOutput : IOutput
  {
    public void Write(string content)
    {
      Console.WriteLine(content);
    }
  }

  // 這個接口將“輸出日期”的概念從具體的輸出方法中解耦。
  public interface IDateWriter
  {
    void WriteDate();
  }

  // TodayWriter 是這些元素匯合在一起的地方。
  // 它的構造函數有一個 IOutput 參數,通過提供不同的實現類,
  // TodayWriter可以將日期寫到不同的地方。
  // 進一步的,在這里WriteDate的實現方式是輸出“今天的日期”,
  // 我們可以用另一個類輸出其他格式,或者其他日期。
  public class TodayWriter : IDateWriter
  {
    private IOutput _output;

    public TodayWriter(IOutput output)
    {
      this._output = output;
    }

    public void WriteDate()
    {
      this._output.Write(DateTime.Today.ToShortDateString());
    }
  }
}

依賴關系

現在我們有了組織良好的依賴關系,接下來引入 Autofac。

添加對 Autofac 的引用

首先向項目添加對Autofac的引用。這個示例中,我們只使用 Autofac 的核心部分。其他類型的應用程序可能需要Autofac 集成庫。

最簡單的方式是使用 NuGet。“Autofac” 程序包包含所有核心功能。

 

 

程序啟動階段

我們在程序啟動時創建 ContainerBuilder 對象,然后向它注冊組件。組件可以是表達式,.NET 類型, 或者其他暴露服務的代碼。組件可以接受其他依賴項。

假設有下面的.net類型:

public class SomeType : IService
{
}

有兩種使用 SomeType 的方式:

- 作為這個類型本身, 也就是聲明為 SomeType

- 作為接口, 也就是聲明為 IService

在這里,組件是 SomeType,它暴露的服務是 SomeType 和 IService。

在 Autofac 中, 使用 ContainerBuilder 注冊組件

// 創建builder
var builder = new ContainerBuilder(); 

// 通常僅通過接口暴露服務
builder.RegisterType<SomeType>().As<IService>(); 

// 但是, 如果同時需要兩種服務(不常見),可以用這種方式:
builder.RegisterType<SomeType>().AsSelf().As<IService>();

在示例程序中,我們要注冊全部組件(類)並暴露他們的服務 (接口),以便他們能連接起來。

我們還需要把容器保存起來,以便稍后使用它解析類型。

using System;
using Autofac; 

namespace DemoApp
{

  public class Program
  {
    private static IContainer Container { get; set; } 

    static void Main(string[] args)
    {
      var builder = new ContainerBuilder();
      builder.RegisterType<ConsoleOutput>().As<IOutput>();
      builder.RegisterType<TodayWriter>().As<IDateWriter>();
      Container = builder.Build(); 

      // The WriteDate method is where we'll make use
      // of our dependency injection. We'll define that
      // in a bit.
      WriteDate();
    }
  }
}

現在,容器里注冊了全部所需的組件和服務,接下來就可以使用容器進行解析。

程序執行階段

程序執行時,通過從范圍(ILifetimeScope對象解析並使用組件。

容器本身即是一個范圍對象,因此可以從容器直接解析類型,但是不推薦這樣做

解析組件時,根據注冊時定義的實例范圍創建一個新的實例。(解析組件類似於使用new操作符) 有些組件需要清理 (比如實現IDisposable接口) -當范圍對象被清理時,Autofac 可以同時清理它所解析的組件。

由於容器對象的生命周期與應用程序相同,如果從容器解析了大量內容, 不被清理的組件會越積越多,造成資源泄露。

相反,我們從容器創建一個范圍對象,然后通過范圍解析對象,范圍對象被清理時,從它解析的組件也一同被清理。

(使用 Autofac 集成庫時,子范圍通常會自動創建。)

對於本示例,“WriteDate” 方法從范圍對象獲取對象,使用結束時只要清理范圍對象。

namespace DemoApp
{
  public class Program
  {
    private static IContainer Container { get; set; } 

    static void Main(string[] args)
    {
      // ...the stuff you saw earlier...
    } 

    public static void WriteDate()
    {
      // 創建范圍,解析 IDateWriter,
      // 使用 writer,最后清理范圍對象。
      using (var scope = Container.BeginLifetimeScope())
      {
        var writer = scope.Resolve<IDateWriter>();
        writer.WriteDate();
      }
    }
  }
}

程序的執行過程如下:

  • “WriteDate” 方法向 Autofac 請求 IDateWriter 實例。
  • Autofac 發現 IDateWriter 映射到 TodayWriter ,於是准備創建一個 TodayWriter 實例。
  • Autofac 發現 TodayWriter 的構造函數需要一個IOutput 實例。
  • Autofac 發現 IOutput 映射到 ConsoleOutput,於是創建一個ConsoleOutput實例。
  • Autofac 使用 ConsoleOutput 實例完成 TodayWriter 的創建。
  • Autofac 返回 TodayWriter。

想輸出另一個日期時,可以實現另一個 IDateWriter,然后更改啟動階段的注冊內容,而不需要更改其他類。這就是控制反轉。

注意: 一般而言,普遍認為服務定位是反模式(請參考這篇文章,服務定位器是反模式) 。換言之,隨處手工創建范圍對象,在代碼中零散的使用容器對象是不好的方式(譯注:autofac 的范圍對象相當於服務定位器)。通過使用Autofac 集成庫 ,可以避免示例代碼中的使用方式。相反,內容在一個位置集中解析,也就是在程序的 “最頂層”位置,極少需要進行手工解析。

更進一步

示例演示了如何使用 Autofac, 您可以繼續了解:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM