Autofac使用config設定Module裡的屬性值

使用Config註冊Module

在某些情境下或是需要註冊的類別太多時,會使用Autofac的Module來封裝註冊資訊,將相關的類別註冊寫在同一個Module裡

public class ServiceModule : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register<TestAService>(p =>
        {
            var testService = new TestAService();
            testService._lifetimeScope = p.Resolve<ILifetimeScope>();
            return testService;
        }).Named<ITestService>("TestAService");
        builder.RegisterType<TestBService>().Named<ITestService>("TestBService");
    }
}

再透過RegisterModule的方式將Module註冊到Autofac的Container內

var builder = new ContainerBuilder();
builder.RegisterModule(new ServiceModule());

AutofacContainer = builder.Build()

如果當某些Module是系統必要註冊時,可以將註冊Module的事情移到Config裡,就不需要在寫在程式碼中。要將註冊Module寫到Config中,必須先安裝Autofac.Configuration,可以從Nuget中找到此套件

Nuget安裝Autofac.configuration 安裝完畢後,需要到App.config或者是Web.config加入以下設定

<configSections>
    <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration" />
</configSections>

再來,就可以將要固定註冊的Module寫到Config中

<autofac>
    <modules>
      <module type="AutofacConstructParameterLandmine_Lab.Model.ServiceModule, AutofacConstructParameterLandmine_Lab">
      </module>
    </modules>
  </autofac>

並且,在程式碼中加入一行程式

builder.RegisterModule(new ConfigurationSettingsReader());

這樣就能會自動註冊寫在Config裡的Module。

附註: module type的格式,第一個為Module完成的名稱,第二個參數為Dll的名稱

使用Config設定Module內的屬性

有時候註冊某些元件時,會直接使用該元件封裝的Module。可是,在特定的情境下可能不需要註冊該元件裡所有的服務。舉個例子來說,當寫一個檔案搬移的元件時,可以同時將檔案複製多個位置,像是本機的硬碟加上網路空間。要達到這樣的功能只要針對不同的位置實作檔案複製的服務即可,再透過一個Manager負責對外讓人呼叫。但是,使用檔案複製元件的人可能沒有網路空間,單純的只是需要將檔案從原本的位置複製到另一個位置時,就不需要註冊檔案複製的所有服務。

這個時候,如果沒有開放參數用使用者設定所需要的服務時,使用者就必須自己註冊該元件要使用的服務,相當的不方便。所以,必須在Module中開放參數來設定要註冊的服務,並且可以將設定的數值寫在Config中。這樣的想法比較常見的做法有兩種

  1. 在Module中讀取Config的設定值
  2. 用Config的Module tag來設定Module中的屬性值

在這邊,筆者比較偏向使用第二個方法。因為,在Module中讀取Config的設定值,比較偏向是讀取服務內所需要的參數,概念上是內部需要的資訊去Config中讀取。而此情境是希望由外部來決定Module的流程,所以第二個方法比較適合。當需要設定Module內的屬性值時,只需要在Module tag中再加上Property tag

<autofac>
    <modules>
      <module type="AutofacConstructParameterLandmine_Lab.Model.ServiceModule, AutofacConstructParameterLandmine_Lab">
        <properties>
          <property name="IsRegisterTestAService" value="true" />
          <property name="IsRegisterTestBService" value="false" />
        </properties>
      </module>
    </modules>
  </autofac>

Configa加上Property tag後,程式中的屬性就會有Config設定的值了

IsRegisterTestAService IsRegisterTestBService

在Module裡就可以靠這些參數來設定哪些服務需要註冊

public class ServiceModule : Autofac.Module
{
    public bool IsRegisterTestAService { get; set; }
    public bool IsRegisterTestBService { get; set; }
    protected override void Load(ContainerBuilder builder)
    {
        if(this.IsRegisterTestAService)
        {
            builder.Register<TestAService>(p =>
            {
                var testService = new TestAService();
                testService._lifetimeScope = p.Resolve<ILifetimeScope>();
                return testService;
            }).Named<ITestService>("TestAService");
        }

        if(this.IsRegisterTestBService)
        {
            builder.RegisterType<TestBService>().Named<ITestService>("TestBService");
        }
    }
}

最後,在Autofac的Container內可以看到只有TestAService被註冊 Autofac註冊結果

結論

Moduel中所需要的參數,可以由不同的方法取得。但是,取得的方式還是必須要合理,上述的例子中,雖然都是讓Module中的變數取得外部設定的數值,但是在概念上是相差很遠的。使用合理概念寫出來的程式,這是很重要的一件事。

免責聲明:

"文章一定有好壞,文章內容有對有錯,使用前應詳閱公開說明書"