Adnc 源码解析
先看 Adnc.Demo.Usr.Api 解决方案
1 2 3 4 5 | var startAssembly = System.Reflection.Assembly.GetExecutingAssembly(); var startAssemblyName = startAssembly.GetName().Name ?? string .Empty; var lastName = startAssemblyName.Split( '.' ).Last(); var migrationsAssemblyName = startAssemblyName.Replace($ ".{lastName}" , ".Repository" ); var serviceInfo = ServiceInfo.CreateInstance(startAssembly, migrationsAssemblyName); |
上面代码 是构建 Adnc.Demo.Usr.Api 服务信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | namespace Adnc.Shared.WebApi; public class ServiceInfo : IServiceInfo { private static ServiceInfo? _instance = null ; private static readonly object _lockObj = new (); public string Id { get ; private set ; } = string .Empty; public string ServiceName { get ; private set ; } = string .Empty; public string CorsPolicy { get ; set ; } = string .Empty; public string ShortName { get ; private set ; } = string .Empty; public string RelativeRootPath { get ; private set ; } = string .Empty; public string Version { get ; private set ; } = string .Empty; public string Description { get ; private set ; } = string .Empty; public Assembly StartAssembly { get ; private set ; } = default !; public string MigrationsAssemblyName { get ; private set ; } = string .Empty; private ServiceInfo() { } public static ServiceInfo CreateInstance(Assembly startAssembly, string ? migrationsAssemblyName = null ) { if (_instance is not null ) return _instance; lock (_lockObj) { if (_instance is not null ) return _instance; if (startAssembly is null ) startAssembly = Assembly.GetEntryAssembly() ?? throw new NullReferenceException(nameof(startAssembly)); var attribute = startAssembly.GetCustomAttribute<AssemblyDescriptionAttribute>(); var description = attribute is null ? string .Empty : attribute.Description; var version = startAssembly.GetName().Version ?? throw new NullReferenceException( "startAssembly.GetName().Version" ); var startAssemblyName = startAssembly.GetName().Name ?? string .Empty; var serviceName = startAssemblyName.Replace( "." , "-" ).ToLower(); var ticks = DateTime.Now.GetTotalMilliseconds().ToLong(); var ticksHex = Convert.ToString(ticks, 16); var envName = Environment.GetEnvironmentVariable( "ASPNETCORE_ENVIRONMENT" )?.ToLower(); var serviceId = envName switch { "development" => $ "{serviceName}-dev-{ticksHex}" , "test" => $ "{serviceName}-test-{ticksHex}" , "staging" => $ "{serviceName}-stag-{ticksHex}" , "production" => $ "{serviceName}-{ticksHex}" , _ => throw new NullReferenceException( "ASPNETCORE_ENVIRONMENT" ) }; var names = startAssemblyName.Split( "." ); migrationsAssemblyName ??= startAssemblyName.Replace($ ".{names.Last()}" , ".Migrations" ); _instance = new ServiceInfo { Id = serviceId, ServiceName = serviceName, ShortName = $ "{names[^2]}-{names[^1]}" .ToLower(), RelativeRootPath = $ "{names[^2]}/{names[^1]}" .ToLower(), CorsPolicy = "default" , StartAssembly = startAssembly, Description = description, Version = $ "{version.Major}.{version.Minor}.{version.Build}.{version.Revision}" , MigrationsAssemblyName = migrationsAssemblyName }; } return _instance; } public static ServiceInfo GetInstance() { if (_instance is null ) throw new NullReferenceException(nameof(ServiceInfo)); return _instance; } } |
上面使用得是单例 模式
注意 这里的 代码 public Assembly StartAssembly { get; private set; } = default!;
StartAssembly 后面需要 用它反射
接下来 这行代码
var app = WebApplication.CreateBuilder(args).ConfigureAdncDefault(serviceInfo).Build();
调用 ConfigureAdncDefault(serviceInfo)
这是一个扩展方法 在 Adnc.Shared.WebApi 解决方案中
public static WebApplicationBuilder ConfigureAdncDefault(this WebApplicationBuilder builder, IServiceInfo serviceInfo)
{
builder.Services.AddAdnc(serviceInfo);
}
调用了 AddAdnc(serviceInfo) 扩展方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public static class ServiceCollectionExtension { /// <summary> /// 统一注册Adnc.WebApi通用服务 /// </summary> /// <param name="services"></param> /// <param name="startupAssembly"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="NullReferenceException"></exception> public static IServiceCollection AddAdnc( this IServiceCollection services, IServiceInfo serviceInfo) { if (serviceInfo?.StartAssembly is null ) throw new ArgumentNullException(nameof(serviceInfo)); var webApiRegistarType = serviceInfo.StartAssembly.ExportedTypes.FirstOrDefault(m => m.IsAssignableTo( typeof (IDependencyRegistrar)) && m.IsAssignableTo( typeof (AbstractWebApiDependencyRegistrar)) && m.IsNotAbstractClass( true )); if (webApiRegistarType is null ) throw new NullReferenceException(nameof(IDependencyRegistrar)); if (Activator.CreateInstance(webApiRegistarType, services) is not IDependencyRegistrar webapiRegistar) throw new NullReferenceException(nameof(webapiRegistar)); webapiRegistar.AddAdnc(); return services; } } |
上面 红色代码 serviceInfo.StartAssembly 通过他反射
创建了 子类 Activator.CreateInstance(webApiRegistarType, services) is not IDependencyRegistrar webapiRegistar
子类也就是 Adnc.Demo.Usr.Api 解决方法中得 UsrWebApiDependencyRegistrar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | using Adnc.Demo.Usr.Api.Authentication; using Adnc.Demo.Usr.Api.Authorization; using Adnc.Shared.WebApi.Registrar; namespace Adnc.Demo.Usr.Api; public sealed class UsrWebApiDependencyRegistrar : AbstractWebApiDependencyRegistrar { public UsrWebApiDependencyRegistrar(IServiceCollection services) : base (services) { } public UsrWebApiDependencyRegistrar(IApplicationBuilder app) : base (app) { } public override void AddAdnc() { AddWebApiDefault<BearerAuthenticationLocalProcessor, PermissionLocalHandler>(); AddHealthChecks( true , true , true , false ); Services.AddGrpc(); } public override void UseAdnc() { UseWebApiDefault(endpointRoute: endpoint => { endpoint.MapGrpcService<Grpc.AuthGrpcServer>(); endpoint.MapGrpcService<Grpc.UsrGrpcServer>(); }); } } |
子类 重写了父类得 AddAdnc() 方法 调用了 父类AbstractWebApiDependencyRegistrar 中得 AddWebApiDefault<BearerAuthenticationLocalProcessor, PermissionLocalHandler>(); 方法 也就是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /// <summary> /// 注册Webapi通用的服务 /// </summary> /// <typeparam name="TAuthenticationProcessor"><see cref="AbstractAuthenticationProcessor"/></typeparam> /// <typeparam name="TAuthorizationHandler"><see cref="AbstractPermissionHandler"/></typeparam> protected virtual void AddWebApiDefault<TAuthenticationProcessor, TAuthorizationHandler>() where TAuthenticationProcessor : AbstractAuthenticationProcessor where TAuthorizationHandler : AbstractPermissionHandler { Services.AddControllers(); Services .AddHttpContextAccessor() .AddMemoryCache(); Configure(); AddControllers(); AddAuthentication<TAuthenticationProcessor>(); AddAuthorization<TAuthorizationHandler>(); AddCors(); var enableSwaggerUI = Configuration.GetValue(NodeConsts.SwaggerUI_Enable, true ); if (enableSwaggerUI) { AddSwaggerGen(); AddMiniProfiler(); } AddApplicationServices(); } |
父类中的 方法 调用了 AddApplicationServices(); 方法
这个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | namespace Adnc.Shared.WebApi.Registrar; public abstract partial class AbstractWebApiDependencyRegistrar { /// <summary> /// 注册Application层服务 /// </summary> protected virtual void AddApplicationServices() { var appAssembly = ServiceInfo.GetApplicationAssembly(); if (appAssembly is not null ) { var applicationRegistrarType = appAssembly.ExportedTypes.FirstOrDefault(m => m.IsAssignableTo( typeof (IDependencyRegistrar)) && !m.IsAssignableTo( typeof (AbstractWebApiDependencyRegistrar)) && m.IsNotAbstractClass( true )); if (applicationRegistrarType is not null ) { var applicationRegistrar = Activator.CreateInstance(applicationRegistrarType, Services) as IDependencyRegistrar; applicationRegistrar?.AddAdnc(); } } } } |
这段代码 ServiceInfo.GetApplicationAssembly(); 获取了 Adnc.Shared.Application 程序集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | using Adnc.Infra.Consul.Configuration; namespace Adnc.Shared.WebApi { public static class ServiceInfoExtension { private static readonly object lockObj = new (); private static Assembly? appAssembly; /// <summary> /// 获取WebApiAssembly程序集 /// </summary> /// <returns></returns> public static Assembly GetWebApiAssembly( this IServiceInfo serviceInfo) => serviceInfo.StartAssembly; /// <summary> /// 获取Application程序集 /// </summary> /// <returns></returns> public static Assembly GetApplicationAssembly( this IServiceInfo serviceInfo) { if (appAssembly is null ) { lock (lockObj) { if (appAssembly is null ) { Assembly startAssembly = serviceInfo.StartAssembly ?? throw new NullReferenceException(nameof(serviceInfo.StartAssembly)); string startAssemblyFullName = startAssembly.FullName ?? throw new NullReferenceException(nameof(startAssembly.FullName)); string startAssemblyName = startAssembly.GetName().Name ?? string .Empty; string lastName = startAssemblyName.Split( "." ).Last(); string appAssemblyFullName = startAssemblyFullName.Replace($ ".{lastName}" , ".Application" ); appAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName == appAssemblyFullName); if (appAssembly is null ) { appAssembly = startAssembly; //appAssembly = Assembly.Load(appAssemblyName); //var appAssemblyPath = serviceInfo.AssemblyLocation.Replace(".WebApi.dll", ".Application.dll"); ///appAssembly = Assembly.LoadFrom(appAssemblyPath); } } } } return appAssembly; } /// <summary> /// 获取导航首页内容 /// </summary> /// <param name="serviceInfo"></param> /// <param name="app"></param> /// <returns></returns> public static string GetDefaultPageContent( this IServiceInfo serviceInfo, IServiceProvider serviceProvider) { var swaggerUrl = $ "/{serviceInfo.RelativeRootPath}/index.html" ; var consulOptions = serviceProvider.GetRequiredService<IOptions<ConsulOptions>>(); var healthCheckUrl = consulOptions?.Value?.HealthCheckUrl ?? $ "/{serviceInfo.RelativeRootPath}/health-24b01005-a76a-4b3b-8fb1-5e0f2e9564fb" ; var envName = Environment.GetEnvironmentVariable( "ASPNETCORE_ENVIRONMENT" ); var content = $ "<div align='center'><a href='https://github.com/alphayu/adnc' target='_blank'><img src='https://aspdotnetcore.net/wp-content/uploads/2023/04/adnc-topics.png'/></a><br>" + $ "ASPNETCORE_ENVIRONMENT = {envName} <br> " + $ "Version = {serviceInfo.Version} <br> " + $ "ServiceName = {serviceInfo.ServiceName} <br> " + $ "ShortName = {serviceInfo.ShortName} <br> " + $ "RelativeRootPath = {serviceInfo.RelativeRootPath} <br> " + $ "<br><a href='{swaggerUrl}'>swagger UI</a> | <a href='{healthCheckUrl}'>healthy checking</a><br>" + $ "<br>{DateTime.Now}</div>" ; return content; } } } |
这段代码
1 2 | <strong> string appAssemblyFullName = startAssemblyFullName.Replace($ ".{lastName}" , ".Application" ); appAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName == appAssemblyFullName);<br>是获取 <strong>Adnc.Shared.Application 程序集</strong></strong> |
这个方法通过反射 构造了 DependencyRegistrar 对象 强调 一下 这是是对 Adnc.Demo.Usr.Application 中的 DependencyRegistrar 构造 对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | namespace Adnc.Demo.Usr.Application; public sealed class DependencyRegistrar : AbstractApplicationDependencyRegistrar { public override Assembly ApplicationLayerAssembly => Assembly.GetExecutingAssembly(); public override Assembly ContractsLayerAssembly => typeof (IUserAppService).Assembly; public override Assembly RepositoryOrDomainLayerAssembly => typeof (EntityInfo).Assembly; public DependencyRegistrar(IServiceCollection services) : base (services) { } public override void AddAdnc() => AddApplicaitonDefault(); } |
1 | Adnc.Demo.Usr.Application 解决方案 DependencyRegistrar 类 重写了 父类方法 |
1 | public override void AddAdnc() => AddApplicaitonDefault(); |
1 | 该方法 AddApplicaitonDefault() 在 Adnc.Shared.Application 解决方案 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /// <summary> /// 注册adnc.application通用服务 /// </summary> protected virtual void AddApplicaitonDefault() { Services .AddValidatorsFromAssembly(ContractsLayerAssembly, ServiceLifetime.Scoped) .AddAdncInfraAutoMapper(ApplicationLayerAssembly) .AddAdncInfraYitterIdGenerater(RedisSection) .AddAdncInfraConsul(ConsulSection) .AddAdncInfraDapper(); AddApplicationSharedServices(); AddAppliactionSerivcesWithInterceptors(); AddApplicaitonHostedServices(); AddEfCoreContextWithRepositories(); AddMongoContextWithRepositries(); AddRedisCaching(); AddBloomFilters(); } |
这里 说明 AddEfCoreContextWithRepositories(); 这个方法 是注册 EF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | using Adnc.Infra.Repository.EfCore.MySql.Configurations; using Adnc.Infra.Repository.Mongo; using Adnc.Infra.Repository.Mongo.Configuration; using Adnc.Infra.Repository.Mongo.Extensions; using Microsoft.EntityFrameworkCore; namespace Adnc.Shared.Application.Registrar; public abstract partial class AbstractApplicationDependencyRegistrar { /// <summary> /// 注册EFCoreContext与仓储 /// </summary> protected virtual void AddEfCoreContextWithRepositories() { var serviceType = typeof (IEntityInfo); var implType = RepositoryOrDomainLayerAssembly.ExportedTypes.FirstOrDefault(type => type.IsAssignableTo(serviceType) && type.IsNotAbstractClass( true )); if (implType is null ) throw new NotImplementedException(nameof(IEntityInfo)); else Services.AddScoped(serviceType, implType); AddEfCoreContext(); } /// <summary> /// 注册EFCoreContext /// </summary> protected virtual void AddEfCoreContext() { var serviceInfo = Services.GetServiceInfo(); var mysqlConfig = MysqlSection.Get<MysqlOptions>(); var serverVersion = new MariaDbServerVersion( new Version(10, 5, 4)); Services.AddAdncInfraEfCoreMySql(options => { options.UseLowerCaseNamingConvention(); options.UseMySql(mysqlConfig.ConnectionString, serverVersion, optionsBuilder => { optionsBuilder.MinBatchSize(4) .MigrationsAssembly(serviceInfo.MigrationsAssemblyName) .UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); }); //if (this.IsDevelopment()) //{ // //options.AddInterceptors(new DefaultDbCommandInterceptor()) // options.LogTo(Console.WriteLine, LogLevel.Information) // .EnableSensitiveDataLogging() // .EnableDetailedErrors(); //} //替换默认查询sql生成器,如果通过mycat中间件实现读写分离需要替换默认SQL工厂。 //options.ReplaceService<IQuerySqlGeneratorFactory, AdncMySqlQuerySqlGeneratorFactory>(); }); } /// <summary> /// 注册MongoContext与仓储 /// </summary> protected virtual void AddMongoContextWithRepositries(Action<IServiceCollection>? action = null ) { action?.Invoke(Services); var mongoConfig = MongoDbSection.Get<MongoOptions>(); Services.AddAdncInfraMongo<MongoContext>(options => { options.ConnectionString = mongoConfig.ConnectionString; options.PluralizeCollectionNames = mongoConfig.PluralizeCollectionNames; options.CollectionNamingConvention = (NamingConvention)mongoConfig.CollectionNamingConvention; }); } } |
其中 Services.AddAdncInfraEfCoreMySql扩展方法 调用得 是 Adnc.Infra.Repository.EfCore.MySql 解决方案 注册了 仓储 这里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using Adnc.Infra.Repository.EfCore.MySql; using Adnc.Infra.Repository.EfCore.MySql.Transaction; namespace Microsoft.Extensions.DependencyInjection; public static class ServiceCollectionExtension { public static IServiceCollection AddAdncInfraEfCoreMySql( this IServiceCollection services, Action<DbContextOptionsBuilder> optionsBuilder) { if (services.HasRegistered(nameof(AddAdncInfraEfCoreMySql))) return services; services.TryAddScoped<IUnitOfWork, MySqlUnitOfWork<MySqlDbContext>>(); services.TryAddScoped( typeof (IEfRepository<>), typeof (EfRepository<>)); services.TryAddScoped( typeof (IEfBasicRepository<>), typeof (EfBasicRepository<>)); services.AddDbContext<DbContext, MySqlDbContext>(optionsBuilder); return services; } } |
这篇 分析了
Adnc.Demo.Usr.Api -----(ConfigureAdncDefault(serviceInfo))---------> Adnc.Shared.WebApi -------- AddAdnc 反射获取子类 子类重写 AddAdnc 调用了父类
AddWebApiDefault.AddApplicationServices 反射出 Adnc.Shared.Application------->
Adnc.Shared.Application ----- (AbstractApplicationDependencyRegistrar.AddApplicaitonDefault.AddEfCoreContextWithRepositories) ----->
Adnc.Infra.Repository.EfCore.MySql
就是 依次 往上调用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律