Autofac 是一個功能豐富的 .NET 依賴註入容器,用於管理對象的生命周期、解決依賴關係以及進行屬性註入。本文將詳細講解 Autofac 的使用方法,包括多種不同的註冊方式,屬性註入,以及如何使用多個 ContainerBuilder 來註冊和合併組件。我們將提供詳細的源代碼示例來說明每個概念 ...
Autofac 是一個功能豐富的 .NET 依賴註入容器,用於管理對象的生命周期、解決依賴關係以及進行屬性註入。本文將詳細講解 Autofac 的使用方法,包括多種不同的註冊方式,屬性註入,以及如何使用多個 ContainerBuilder 來註冊和合併組件。我們將提供詳細的源代碼示例來說明每個概念。
1. 安裝 Autofac
首先,確保你已經安裝了 Autofac NuGet 包。你可以使用 NuGet 包管理器或通過控制台運行以下命令來安裝 Autofac:
Install-Package Autofac
2. 創建一個簡單的控制台應用程式
我們將從一個簡單的控制台應用程式開始,以演示 Autofac 的基本用法。我們將創建一個包含多個組件的容器,並演示多種註冊方式以及屬性註入的方法。
Program.cs
using System;
using Autofac;
namespace AutofacExample
{
class Program
{
static void Main(string[] args)
{
// 步驟 1:創建 ContainerBuilder
var builder = new ContainerBuilder();
// 步驟 2:註冊組件
builder.RegisterType<DatabaseConnection>().As<IDatabaseConnection>().SingleInstance();
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();
builder.RegisterType<Logger>().As<ILogger>().Named<ILogger>("ConsoleLogger");
// 步驟 3:構建容器
var container = builder.Build();
// 步驟 4:解析組件併進行屬性註入
using (var scope = container.BeginLifetimeScope())
{
var userRepository = scope.Resolve<IUserRepository>();
userRepository.AddUser("John Doe");
// 屬性註入示例
var logger = scope.ResolveNamed<ILogger>("ConsoleLogger");
logger.Log("This is a log message with attribute injection.");
}
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
}
}
3. 創建組件和介面
現在,我們將創建三個組件 DatabaseConnection,UserRepository 和 Logger,以及它們所實現的介面。
DatabaseConnection.cs
public interface IDatabaseConnection
{
void Connect();
}
public class DatabaseConnection : IDatabaseConnection
{
public void Connect()
{
Console.WriteLine("Connected to the database.");
}
}
UserRepository.cs
public interface IUserRepository
{
void AddUser(string username);
}
public class UserRepository : IUserRepository
{
private readonly IDatabaseConnection _databaseConnection;
public UserRepository(IDatabaseConnection databaseConnection)
{
_databaseConnection = databaseConnection;
}
public void AddUser(string username)
{
_databaseConnection.Connect();
Console.WriteLine($"User '{username}' added to the database.");
}
}
Logger.cs
public interface ILogger
{
void Log(string message);
}
public class Logger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"Logging: {message}");
}
}
4. 多種註冊方式
Autofac 提供了多種不同的組件註冊方式,允許你控制組件的生命周期、解決複雜的依賴關係和應用更高級的用法。以下是一些常見的註冊方式:
4.1. 單例註冊
你可以註冊一個組件為單例,這意味著容器將返回同一個實例,直到容器被銷毀。在示例中,我們使用 SingleInstance() 方法將 DatabaseConnection 註冊為單例。
builder.RegisterType<DatabaseConnection>().As<IDatabaseConnection>().SingleInstance();
4.2. 生命周期範圍註冊
你可以將組件註冊為具有特定生命周期範圍,例如單次請求或單個生命周期。在示例中,我們使用 InstancePerLifetimeScope() 方法將 UserRepository 註冊為單個生命周期。
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();
4.3. 命名註冊
你可以註冊組件併為其指定一個名稱,以便在解析時根據名稱來選擇不同的實現。在示例中,我們使用 Named<TService, TImplementer>(string name) 方法為 Logger 註冊一個名為 "ConsoleLogger" 的實現。
builder.RegisterType<Logger>().As<ILogger>().Named<ILogger>("ConsoleLogger");
4.4. Lambda 表達式註冊
你可以使用 Lambda 表達式註冊一個組件,以根據需要創建實例。在示例中,我們使用 Lambda 表達式註冊 DatabaseConnection。
builder.Register(c => new DatabaseConnection()).As<IDatabaseConnection>();
4.5. 泛型組件註冊
你可以註冊泛型組件,允許你在解析時提供類型參數。在示例中,我們使用 RegisterGeneric 方法註冊泛型組件 GenericRepository<T>。
builder.RegisterGeneric(typeof(GenericRepository<>)).As(typeof(IGenericRepository<>));
5. 屬性註入
Autofac 允許你進行屬性註入,這意味著你可以在組件實例化後註入屬性的值。在示例中,我們演示瞭如何使用屬性註入將 ILogger 註入到 UserRepository 中。
首先,我們需要為 UserRepository 類添加一個屬性,並使用 [Autowired] 特性進行標記:
public class UserRepository : IUserRepository
{
private readonly IDatabaseConnection _databaseConnection;
// 使用 [Autowired] 特性進行屬性註入
[Autowired]
public ILogger Logger { get; set; }
public UserRepository(IDatabaseConnection databaseConnection)
{
_databaseConnection = databaseConnection;
}
public void AddUser(string username)
{
_databaseConnection.Connect();
Console.WriteLine($"User '{username}' added to the database.");
// 使用註入的 Logger
Logger.Log("User added.");
}
}
接下來,我們需要在容器構建前啟用屬性註入。這可以通過配置 ContainerBuilder 來實現:
var builder = new ContainerBuilder();
builder.RegisterType<DatabaseConnection>().As<IDatabaseConnection>().SingleInstance
();
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();
builder.RegisterType<Logger>().As<ILogger>().Named<ILogger>("ConsoleLogger");
// 啟用屬性註入
builder.RegisterCallback(PropertyInjector.InjectProperties);
var container = builder.Build();
現在,當 UserRepository 被解析時,Logger 屬性將自動註入,從而實現屬性註入。
6. 使用多個ContainerBuilder合併註冊
有時候,你可能需要在不同的模塊或程式部分中註冊組件。對於這種情況,你可以使用多個 ContainerBuilder 對象,並最終將它們合併到一個主容器中。下麵是如何實現這一點的示例:
Program.cs(擴展)
在上面的示例中,我們已經創建了一個容器並註冊了組件。現在,我們將添加一個額外的 ContainerBuilder,註冊另一個組件,然後將它們合併。
// 步驟 7:使用另一個 ContainerBuilder 註冊另一個組件
var builder2 = new ContainerBuilder();
builder2.RegisterType<EmailSender>().As<IEmailSender>();
// 步驟 8:合併 ContainerBuilder
builder.Update(builder2);
EmailSender.cs
public interface IEmailSender
{
void SendEmail(string to, string subject, string message);
}
public class EmailSender : IEmailSender
{
public void SendEmail(string to, string subject, string message)
{
Console.WriteLine($"Sending email to {to} with subject: {subject}");
Console.WriteLine($"Message: {message}");
}
}
現在,我們已經註冊了一個名為 EmailSender 的額外組件,並將其合併到主容器中。
7. 使用多個 ContainerBuilder 示例
這是完整的示例代碼:
Program.cs(完整)
using System;
using Autofac;
namespace AutofacExample
{
class Program
{
static void Main(string[] args)
{
// 步驟 1:創建 ContainerBuilder
var builder = new ContainerBuilder();
// 步驟 2:註冊組件
builder.RegisterType<DatabaseConnection>().As<IDatabaseConnection>().SingleInstance();
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();
builder.RegisterType<Logger>().As<ILogger>().Named<ILogger>("ConsoleLogger");
// 步驟 3:構建容器
var container = builder.Build();
// 步驟 4:解析組件併進行屬性註入
using (var scope = container.BeginLifetimeScope())
{
var userRepository = scope.Resolve<IUserRepository>();
userRepository.AddUser("John Doe");
// 屬性註入示例
var logger = scope.ResolveNamed<ILogger>("ConsoleLogger");
logger.Log("This is a log message with attribute injection.");
}
// 步驟 7:使用另一個 ContainerBuilder 註冊另一個組件
var builder2 = new ContainerBuilder();
builder2.RegisterType<EmailSender>().As<IEmailSender>();
// 步驟 8:合併 ContainerBuilder
builder.Update(builder2);
// 步驟 9:解析新組件
using (var scope = container.BeginLifetimeScope())
{
var emailSender = scope.Resolve<IEmailSender>();
emailSender.SendEmail("[email protected]", "Hello", "This is a test email.");
}
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
}
}
這個示例演示瞭如何使用多個 ContainerBuilder 註冊不同的組件,並將它們合併到一個容器中。當程式運行時,它會輸出以下內容:
Connected to the database.
User 'John Doe' added to the database.
Logging: This is a log message with attribute injection.
Sending email to [email protected] with subject: Hello
Message: This is a test email.
Press Enter to exit...
這表明我們成功註冊和合併了不同的組件,並且它們可以一起工作。
Autofac 是一個強大的 .NET 依賴註入容器,它提供了多種註冊方式、屬性註入以及合併多個 ContainerBuilder 的功能,使你能夠更靈活地管理對象的生命周期和解決依賴關係。希望這個示例能夠幫助你更好地理解 Autofac 的使用方式,併在你的.NET 項目中更好地應用依賴註入。Autofac 的強大功能使它成為一個優秀的依賴註入容器,適用於各種應用場景。