.NET基于類名約定的自動依賴注入最佳實踐指南
?? .NET基于類名約定的自動依賴注入完整指南
基于類名約定的自動依賴注入可大幅減少手動注冊服務的工作量,本文將通過清晰的結(jié)構(gòu)、美觀的排版和豐富的示例,幫助你快速掌握這一實用技術。
?? 核心特性概覽
| 特性 | 說明 |
|---|---|
| 類名約定 | 自動識別以 Service 結(jié)尾的類(不區(qū)分大小寫) |
| 接口優(yōu)先匹配 | 優(yōu)先注冊到 I{ClassName} 形式的接口(如 UserService → IUserService) |
| 多生命周期支持 | 支持 Transient/Scoped/Singleton 三種生命周期 |
| 靈活掃描控制 | 可指定任意程序集或默認掃描調(diào)用程序集 |
| 無接口自注冊 | 自動注冊未實現(xiàn)接口的類為自身類型 |
?? 完整代碼實現(xiàn)(含所有重載)
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Reflection;
/// <summary>
/// 依賴注入擴展方法集合(基于類名約定)
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// 自動注冊以"Service"結(jié)尾的類(默認Transient生命周期)
/// </summary>
public static IServiceCollection AutoRegisterServices(
this IServiceCollection services,
Assembly assembly = null)
{
assembly ??= Assembly.GetCallingAssembly();
// 掃描規(guī)則:公共類、非抽象、非泛型、類名以Service結(jié)尾
var serviceTypes = assembly.GetTypes()
.Where(t =>
t.IsClass && !t.IsAbstract && t.IsPublic &&
!t.ContainsGenericParameters &&
t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase))
.ToArray();
// 注冊服務到容器
foreach (var implType in serviceTypes)
{
var interfaces = implType.GetInterfaces();
if (interfaces.Any())
{
// 匹配I{ClassName}接口(如UserService→IUserService)
var matchingInterface = interfaces.FirstOrDefault(i =>
i.Name == "I" + implType.Name);
if (matchingInterface != null)
{
services.AddTransient(matchingInterface, implType);
}
else
{
// 注冊到所有實現(xiàn)的接口
foreach (var @interface in interfaces)
{
services.AddTransient(@interface, implType);
}
}
}
else
{
// 無接口時注冊自身
services.AddTransient(implType);
}
}
return services;
}
/// <summary>
/// 自動注冊以"Service"結(jié)尾的類(支持自定義生命周期)
/// </summary>
public static IServiceCollection AutoRegisterServices(
this IServiceCollection services,
ServiceLifetime lifetime,
Assembly assembly = null)
{
assembly ??= Assembly.GetCallingAssembly();
var serviceTypes = GetServiceTypes(assembly);
foreach (var implType in serviceTypes)
{
var interfaces = implType.GetInterfaces();
var descriptor = CreateServiceDescriptor(implType, interfaces, lifetime);
services.Add(descriptor);
}
return services;
}
// 輔助方法:獲取服務類型(提取公共邏輯)
private static Type[] GetServiceTypes(Assembly assembly) =>
assembly.GetTypes()
.Where(t =>
t.IsClass && !t.IsAbstract && t.IsPublic &&
!t.ContainsGenericParameters &&
t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase))
.ToArray();
// 輔助方法:創(chuàng)建服務描述符(提取公共邏輯)
private static ServiceDescriptor CreateServiceDescriptor(
Type implType, Type[] interfaces, ServiceLifetime lifetime)
{
if (interfaces.Any())
{
var matchingInterface = interfaces.FirstOrDefault(i =>
i.Name == "I" + implType.Name);
if (matchingInterface != null)
{
return new ServiceDescriptor(matchingInterface, implType, lifetime);
}
// 返回第一個接口(避免注冊多個描述符)
return new ServiceDescriptor(interfaces[0], implType, lifetime);
}
return new ServiceDescriptor(implType, implType, lifetime);
}
}?? 使用示例(清晰排版)
1. 在ASP.NET Core中注冊(Program.cs)
var builder = WebApplication.CreateBuilder(args);
// 方式1:默認Transient(掃描調(diào)用程序集)
builder.Services.AutoRegisterServices();
// 方式2:指定Scoped生命周期
builder.Services.AutoRegisterServices(ServiceLifetime.Scoped);
// 方式3:掃描指定程序集(如業(yè)務層)
var businessAssembly = Assembly.Load("MyBusinessLayer");
builder.Services.AutoRegisterServices(ServiceLifetime.Singleton, businessAssembly);
var app = builder.Build();2. 服務類示例(符合約定的實現(xiàn))
// ? 示例1:接口匹配型服務
public interface IUserService { string GetInfo(); }
public class UserService : IUserService
{
public string GetInfo() => "User Service Running";
}
// ? 示例2:多接口實現(xiàn)服務
public interface IAuthService { void Login(); }
public interface ILogService { void WriteLog(string msg); }
public class AuthService : IAuthService, ILogService
{
public void Login() { /* 登錄邏輯 */ }
public void WriteLog(string msg) { /* 日志邏輯 */ }
}
// ? 示例3:無接口自注冊服務
public class DataService
{
public void ProcessData() { /* 數(shù)據(jù)處理 */ }
}
// ? 示例4:不符合約定的類(不會被注冊)
public class ServiceHelper { } // 類名不以Service結(jié)尾
public abstract class BaseService { } // 抽象類?? 擴展優(yōu)化方案(帶emoji標記)
1. ?? 基于類名的生命周期自動識別
private static ServiceLifetime GetLifetimeFromName(string className)
{
if (className.Contains("Singleton", StringComparison.OrdinalIgnoreCase))
return ServiceLifetime.Singleton;
if (className.Contains("Scoped", StringComparison.OrdinalIgnoreCase))
return ServiceLifetime.Scoped;
return ServiceLifetime.Transient;
}2. ?? 特性標記增強控制
[AttributeUsage(AttributeTargets.Class)]
public class AutoRegisterAttribute : Attribute
{
public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Transient;
public bool IsEnabled { get; set; } = true;
}3. ? 緩存掃描結(jié)果提升性能
private static readonly object LockObj = new();
private static Type[] _cachedServiceTypes;
private static Type[] GetCachedServiceTypes(Assembly assembly)
{
if (_cachedServiceTypes == null)
{
lock (LockObj)
{
_cachedServiceTypes = assembly.GetTypes()
.Where(t => /* 掃描規(guī)則 */)
.ToArray();
}
}
return _cachedServiceTypes;
}?? 最佳實踐指南
?? 混合注冊策略
- 核心服務(如DbContext)手動注冊:
services.AddDbContext<AppDbContext>(options => {...}); - 業(yè)務服務自動注冊:
builder.Services.AutoRegisterServices();
- 核心服務(如DbContext)手動注冊:
?? 精準掃描范圍
// 僅掃描當前程序集中的服務 builder.Services.AutoRegisterServices(typeof(UserService).Assembly);
? 單元測試驗證
[Fact]
public void Should_Resolve_Service_By_Convention()
{
var services = new ServiceCollection();
services.AutoRegisterServices(typeof(IAuthService).Assembly);
var provider = services.BuildServiceProvider();
var service = provider.GetService<IAuthService>();
Assert.NotNull(service);
}到此這篇關于.NET基于類名約定的自動依賴注入完整指南的文章就介紹到這了,更多相關.net自動依賴注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
動態(tài)ItemTemplate的實現(xiàn)(譯) - item,template
動態(tài)ItemTemplate的實現(xiàn)(譯) - item,template...2007-02-02
在asp.net中操作sql server數(shù)據(jù)庫的一些小技巧
在asp.net中操作sql server數(shù)據(jù)庫的一些小技巧...2006-09-09
無法將類型為“System.Web.UI.WebControls.HiddenField”的對象強制轉(zhuǎn)換為類型的錯誤的解
無法將類型為“System.Web.UI.WebControls.HiddenField”的對象強制轉(zhuǎn)換為類型的錯誤的解決方法2011-12-12
.NET Core中創(chuàng)建和使用NuGet包的示例代碼
這篇文章主要介紹了.NET Core中創(chuàng)建和使用NuGet包的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04
ASP.NET?Core?WebApi返回結(jié)果統(tǒng)一包裝實踐記錄
本文主要是展示了針對ASP.NET Core WeApi結(jié)果統(tǒng)一返回格式的相關操作,通過示例我們一步一步的展示了完成這一目標的不斷升級的實現(xiàn),雖然整體看起來比較簡單,但是卻承載著筆者一次又一次的思考升級2022-04-04
asp.net Javascript獲取CheckBoxList的value
最近在做一個BS的小項目,記得自己搞asp.net的時候,還是兩年以前,大部分的東西只是有點印象,忘得差不多了,所以這次也算是溫習的過程吧,一邊學習,一邊趕工,呵呵呵。。。。2009-12-12
創(chuàng)建一個ASP.NET MVC5項目的實現(xiàn)方法(圖文)
這篇文章主要介紹了創(chuàng)建一個ASP.NET MVC 5項目,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09

