diff --git a/README.md b/README.md index 084f1ce7f5b56df1cd6b7fa71971787f0ba72010..640d539642d92cecbd93c90fc8c8f028752c421f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ ## 介绍 模块注入模块引用 设计灵感来源于ABPModule,简化了很多没有必要的依赖,可自动扩展工具 +/test/的Demo项目是一个完整的项目示例,有兴趣的可以查看阅读 ## 使用教程 ```csharp @@ -17,7 +18,12 @@ var builder = WebApplication.CreateBuilder(args); // 执行这一步的时候就会先执行NetCoreTestModule里面的 ConfigureService方法, // 执行顺序ConfigureServicesAsync =》ConfigureService方法 // 如果NetCoreTestModule中使用了[DependOn(typeof(其他的Module))] 这样就可以按照传入顺序一并执行 +// 默认自动依赖注入继承指定依赖生命周期的接口 builder.Services.AddTagApplication(); + +// 这样将不会自动依赖注入 +builder.Services.AddTagApplication(false); + var app = builder.Build(); // 执行这一步的时候就会先执行NetCoreTestModule里面的 OnApplicationShutdown, @@ -26,5 +32,41 @@ app.InitializeApplication(); app.Run(); ``` + +## 自动依赖注入 + +// 如果没有取消自动注入的话,您只需要在实现类继承相应的接口即可 +// 接口的名字和实现类型的名字必须基本一致,接口多加I其他的名字必须一致 +IScopedDependency => services.AddScoped(); +ISingletonDependency => service.AddSingleton(); +ITransientDependency => service.AddTransient(); + +### 示例 +```csharp +// 接口 +public interface IDemoService +{ + Task GetAsync(); + + Task UpdateAsync(Guid id,string data); +} + +// 实现类 +public class DemoService : IDemoService, ISingletonDependency +{ + public Task GetAsync() + { + + return Task.FromResult("ok"); + } + + public async Task UpdateAsync(Guid id, string data) + { + await Task.CompletedTask; + } +} +// 只需要按照这个示例就可以完成注入了,必须是未忽略自动注入才会注入 +// 建议按照abp官方的DDD实践去项目划分 +``` ## 测试 在test文件中存在简单的使用示例 diff --git a/Token.Module.sln b/Token.Module.sln index e7fad7f7bfb134f865a1c8329d9cb40c9aae283f..31d54a304b429f4478eb422e744168f5e2b63083 100644 --- a/Token.Module.sln +++ b/Token.Module.sln @@ -10,6 +10,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCoreTest", "test\NetCore EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCore.Application", "test\NetCore.Application\NetCore.Application.csproj", "{A94CBD58-553E-4D40-BDC0-4E10F5D2D0AF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCore.Application.Contracts", "test\NetCore.Application.Contracts\NetCore.Application.Contracts.csproj", "{AF7D627E-4C57-4098-A12A-6226849D6ED4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCore.Domain", "test\NetCore.Domain\NetCore.Domain.csproj", "{BC0E066D-2588-489A-BEAD-7B0B3688F57F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetCore.HttpApi", "test\NetCore.HttpApi\NetCore.HttpApi.csproj", "{C4F54288-4F2E-49E2-A7C4-6D492B32C5E8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -28,10 +34,25 @@ Global {A94CBD58-553E-4D40-BDC0-4E10F5D2D0AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {A94CBD58-553E-4D40-BDC0-4E10F5D2D0AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {A94CBD58-553E-4D40-BDC0-4E10F5D2D0AF}.Release|Any CPU.Build.0 = Release|Any CPU + {AF7D627E-4C57-4098-A12A-6226849D6ED4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF7D627E-4C57-4098-A12A-6226849D6ED4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF7D627E-4C57-4098-A12A-6226849D6ED4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF7D627E-4C57-4098-A12A-6226849D6ED4}.Release|Any CPU.Build.0 = Release|Any CPU + {BC0E066D-2588-489A-BEAD-7B0B3688F57F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC0E066D-2588-489A-BEAD-7B0B3688F57F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC0E066D-2588-489A-BEAD-7B0B3688F57F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC0E066D-2588-489A-BEAD-7B0B3688F57F}.Release|Any CPU.Build.0 = Release|Any CPU + {C4F54288-4F2E-49E2-A7C4-6D492B32C5E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4F54288-4F2E-49E2-A7C4-6D492B32C5E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4F54288-4F2E-49E2-A7C4-6D492B32C5E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4F54288-4F2E-49E2-A7C4-6D492B32C5E8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {F7A2E814-16AB-4B76-8752-00BCF739B7B3} = {F31D9006-FE20-41D9-993B-628745FC639D} {3890287B-4312-476C-B640-A7D0ABC31BD9} = {F83830C2-11E8-4180-93D4-BFA38EDF21E9} {A94CBD58-553E-4D40-BDC0-4E10F5D2D0AF} = {F83830C2-11E8-4180-93D4-BFA38EDF21E9} + {AF7D627E-4C57-4098-A12A-6226849D6ED4} = {F83830C2-11E8-4180-93D4-BFA38EDF21E9} + {BC0E066D-2588-489A-BEAD-7B0B3688F57F} = {F83830C2-11E8-4180-93D4-BFA38EDF21E9} + {C4F54288-4F2E-49E2-A7C4-6D492B32C5E8} = {F83830C2-11E8-4180-93D4-BFA38EDF21E9} EndGlobalSection EndGlobal diff --git a/src/Token.Module/Dependencys/IScopedDependency.cs b/src/Token.Module/Dependencys/IScopedDependency.cs new file mode 100644 index 0000000000000000000000000000000000000000..d99d614b82a9539ccaedeb67b8433eb4a65b1284 --- /dev/null +++ b/src/Token.Module/Dependencys/IScopedDependency.cs @@ -0,0 +1,9 @@ +namespace Token.Module.Dependencys; + +/// +/// Scoped 区域生命周期 +/// +public interface IScopedDependency +{ + +} \ No newline at end of file diff --git a/src/Token.Module/Dependencys/ISingletonDependency.cs b/src/Token.Module/Dependencys/ISingletonDependency.cs new file mode 100644 index 0000000000000000000000000000000000000000..6d4a103659eb6b75186fee0939ce07136877472d --- /dev/null +++ b/src/Token.Module/Dependencys/ISingletonDependency.cs @@ -0,0 +1,9 @@ +namespace Token.Module.Dependencys; + +/// +/// Singleton 单例生命周期 +/// +public interface ISingletonDependency +{ + +} \ No newline at end of file diff --git a/src/Token.Module/Dependencys/ITransientDependency.cs b/src/Token.Module/Dependencys/ITransientDependency.cs new file mode 100644 index 0000000000000000000000000000000000000000..c15042fc962fa20828ec21f2f5d64b46edaa2a8f --- /dev/null +++ b/src/Token.Module/Dependencys/ITransientDependency.cs @@ -0,0 +1,9 @@ +namespace Token.Module.Dependencys; + +/// +/// Transient 瞬时生命周期 +/// +public interface ITransientDependency +{ + +} \ No newline at end of file diff --git a/src/Token.Module/Extensions/DependencyExtensions.cs b/src/Token.Module/Extensions/DependencyExtensions.cs new file mode 100644 index 0000000000000000000000000000000000000000..285a755e600591acb3eda505d4d53443a615c048 --- /dev/null +++ b/src/Token.Module/Extensions/DependencyExtensions.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Token.Module.Dependencys; + +namespace Token.Module.Extensions; + +public static class DependencyExtensions +{ + public static void AddAutoInject(this IServiceCollection services, List tokenModules) + { + var assemblies = tokenModules.Select(x => x.GetType().Assembly).Distinct() + .SelectMany(x => x.GetTypes()); + + var types = assemblies + .Where(type => typeof(ISingletonDependency).IsAssignableFrom(type) || + typeof(IScopedDependency).IsAssignableFrom(type) || + typeof(ITransientDependency).IsAssignableFrom(type)); + + foreach (var t in types) + { + var interfaces = t.GetInterfaces().Where(x => x.Name.EndsWith(t.Name))?.FirstOrDefault(); + + if (interfaces != null) + { + if (typeof(ITransientDependency).IsAssignableFrom(t)) + { + services.AddTransient(interfaces, t); + } + else if (typeof(IScopedDependency).IsAssignableFrom(t)) + { + services.AddScoped(interfaces, t); + } + else if (typeof(ISingletonDependency).IsAssignableFrom(t)) + { + services.AddSingleton(interfaces, t); + } + } + else + { + if (typeof(ITransientDependency).IsAssignableFrom(t)) + { + services.AddTransient(t); + } + else if (typeof(IScopedDependency).IsAssignableFrom(t)) + { + services.AddScoped(t); + } + else if (typeof(ISingletonDependency).IsAssignableFrom(t)) + { + services.AddSingleton(t); + } + } + } + + types = null; + assemblies = null; + } +} \ No newline at end of file diff --git a/src/Token.Module/Extensions/ServiceCollectionApplicationExtensions.cs b/src/Token.Module/Extensions/ServiceCollectionApplicationExtensions.cs index 6a0f0a548f13ae030e0e51ba8bc8f3add0479965..1d9050cdb564d249615e3f55747275d7f341f8d4 100644 --- a/src/Token.Module/Extensions/ServiceCollectionApplicationExtensions.cs +++ b/src/Token.Module/Extensions/ServiceCollectionApplicationExtensions.cs @@ -14,12 +14,13 @@ public static class ServiceCollectionApplicationExtensions /// 初始化Service /// /// + /// 是否自动依赖注入 /// - public static async Task AddTagApplication(this IServiceCollection services) where TModule : ITokenModule + public static async Task AddTagApplication(this IServiceCollection services,bool isAutoInject=true) where TModule : ITokenModule { var types = new List(); var type = typeof(TModule); - var attributes = type.GetCustomAttributes().OfType() + var attributes = type.GetCustomAttributes().OfType() .SelectMany(x => x.Type); var module = type.Assembly.CreateInstance(type.FullName, true) as ITokenModule; @@ -33,8 +34,11 @@ public static class ServiceCollectionApplicationExtensions types.Add(ts); await ts.ConfigureServicesAsync(services); } - services.AddSingleton(types); + if (isAutoInject) + { + services.AddAutoInject(types); + } } /// diff --git a/src/Token.Module/Token.Module.csproj b/src/Token.Module/Token.Module.csproj index 3372886d9fdd56ee10a815e51347eab484aea4f7..815a3f2902e80b61e8119a330be311873f33b11f 100644 --- a/src/Token.Module/Token.Module.csproj +++ b/src/Token.Module/Token.Module.csproj @@ -10,10 +10,10 @@ true https://github.com/239573049/token-module https://github.com/239573049/token-module - 模块注入模块引用 -设计灵感来源于ABPModule,简化了很多没有必要的依赖,可自动扩展工具 + 增加主动依赖注入自动化, + logo.png - 1.0.1 + 1.1.0 diff --git a/test/NetCore.Application.Contracts/NetCore.Application.Contracts.csproj b/test/NetCore.Application.Contracts/NetCore.Application.Contracts.csproj new file mode 100644 index 0000000000000000000000000000000000000000..72d175dd0f34324fb653e5cfb513e28581e7d29a --- /dev/null +++ b/test/NetCore.Application.Contracts/NetCore.Application.Contracts.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/test/NetCore.Application.Contracts/NetCoreApplicationContractsModule.cs b/test/NetCore.Application.Contracts/NetCoreApplicationContractsModule.cs new file mode 100644 index 0000000000000000000000000000000000000000..777e577553e8dbe45175ca707964fd16d87b0c94 --- /dev/null +++ b/test/NetCore.Application.Contracts/NetCoreApplicationContractsModule.cs @@ -0,0 +1,8 @@ +using Token.Module; + +namespace NetCore.Application.Contracts; + +public class NetCoreApplicationContractsModule : TokenModule +{ + +} \ No newline at end of file diff --git a/test/NetCore.Application.Contracts/Services/IDemoService.cs b/test/NetCore.Application.Contracts/Services/IDemoService.cs new file mode 100644 index 0000000000000000000000000000000000000000..13c722ea124900681b6d23fccf05bbef41ddb096 --- /dev/null +++ b/test/NetCore.Application.Contracts/Services/IDemoService.cs @@ -0,0 +1,8 @@ +namespace NetCore.Application.Contracts.Services; + +public interface IDemoService +{ + Task GetAsync(); + + Task UpdateAsync(Guid id,string data); +} \ No newline at end of file diff --git a/test/NetCore.Application/NetCore.Application.csproj b/test/NetCore.Application/NetCore.Application.csproj index 72d175dd0f34324fb653e5cfb513e28581e7d29a..02f46b34845375fbda5a8627b46f5f18890a3ab5 100644 --- a/test/NetCore.Application/NetCore.Application.csproj +++ b/test/NetCore.Application/NetCore.Application.csproj @@ -8,6 +8,14 @@ + + + + + + + + diff --git a/test/NetCore.Application/NetCoreApplicationModule.cs b/test/NetCore.Application/NetCoreApplicationModule.cs index 91129dda79185d9de221826767f2aa493fe22fc5..ae9f6968e26ec9986a31b9e9c1a6cca947da6bb9 100644 --- a/test/NetCore.Application/NetCoreApplicationModule.cs +++ b/test/NetCore.Application/NetCoreApplicationModule.cs @@ -1,9 +1,16 @@ using Token.Module; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; +using NetCore.Application.Contracts; +using NetCore.Domain; +using Token.Module.Attributes; namespace NetCore.Application; +[DependOn( + typeof(NetCoreApplicationContractsModule), + typeof(NetCoreDomainModule) + )] public class NetCoreApplicationModule:TokenModule { public override void ConfigureServices(IServiceCollection services) @@ -13,6 +20,6 @@ public class NetCoreApplicationModule:TokenModule public override void OnApplicationShutdown(IApplicationBuilder app) { - } + } \ No newline at end of file diff --git a/test/NetCore.Application/Services/DemoService.cs b/test/NetCore.Application/Services/DemoService.cs new file mode 100644 index 0000000000000000000000000000000000000000..8ec6823b61bb373adfc38bc6bf9312cf3c004dbb --- /dev/null +++ b/test/NetCore.Application/Services/DemoService.cs @@ -0,0 +1,18 @@ +using NetCore.Application.Contracts.Services; +using Token.Module.Dependencys; + +namespace NetCore.Application.Services; + +public class DemoService : IDemoService, ISingletonDependency +{ + public Task GetAsync() + { + + return Task.FromResult("ok"); + } + + public async Task UpdateAsync(Guid id, string data) + { + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/test/NetCore.Domain/Constant.cs b/test/NetCore.Domain/Constant.cs new file mode 100644 index 0000000000000000000000000000000000000000..c8f259a664bef2519fd538169c0fddaf25119dba --- /dev/null +++ b/test/NetCore.Domain/Constant.cs @@ -0,0 +1,6 @@ +namespace NetCore.Domain; + +public class Constant +{ + public const string Cors = "CorsPolicy"; +} \ No newline at end of file diff --git a/test/NetCore.Domain/NetCore.Domain.csproj b/test/NetCore.Domain/NetCore.Domain.csproj new file mode 100644 index 0000000000000000000000000000000000000000..72d175dd0f34324fb653e5cfb513e28581e7d29a --- /dev/null +++ b/test/NetCore.Domain/NetCore.Domain.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/test/NetCore.Domain/NetCoreDomainModule.cs b/test/NetCore.Domain/NetCoreDomainModule.cs new file mode 100644 index 0000000000000000000000000000000000000000..fc35f821f55602933209ee50f120ef710d3afef4 --- /dev/null +++ b/test/NetCore.Domain/NetCoreDomainModule.cs @@ -0,0 +1,8 @@ +using Token.Module; +using Token.Module.Attributes; + +namespace NetCore.Domain; + +public class NetCoreDomainModule : TokenModule +{ +} \ No newline at end of file diff --git a/test/NetCore.HttpApi/NetCore.HttpApi.csproj b/test/NetCore.HttpApi/NetCore.HttpApi.csproj new file mode 100644 index 0000000000000000000000000000000000000000..f732973604f38a935be4f948acc2c11c3f07b110 --- /dev/null +++ b/test/NetCore.HttpApi/NetCore.HttpApi.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/test/NetCore.HttpApi/NetCoreHttpApiModule.cs b/test/NetCore.HttpApi/NetCoreHttpApiModule.cs new file mode 100644 index 0000000000000000000000000000000000000000..b86ac895723497aa27f78f8668326698da407139 --- /dev/null +++ b/test/NetCore.HttpApi/NetCoreHttpApiModule.cs @@ -0,0 +1,98 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi.Models; +using NetCore.Domain; +using Token.Module; + +namespace NetCore.HttpApi; + +public class NetCoreHttpApiModule : TokenModule +{ + public override void ConfigureServices(IServiceCollection services) + { + ConfigSwagger(services); + ConfigCors(services); + } + + private void ConfigCors(IServiceCollection services) + { + services.AddCors(options => + { + options.AddPolicy(Constant.Cors, corsBuilder => + { + corsBuilder.SetIsOriginAllowed((string _) => true).AllowAnyMethod().AllowAnyHeader() + .AllowCredentials(); + }); + }); + } + + private void ConfigSwagger(IServiceCollection services) + { + services.AddSwaggerGen(o => + { + string[] files = Directory.GetFiles(AppContext.BaseDirectory, "*.xml"); //获取api文档 + string[] array = files; + foreach (string filePath in array) + { + o.IncludeXmlComments(filePath, includeControllerXmlComments: true); + } + + o.SwaggerDoc("v1", new OpenApiInfo + { + Title = "token API", + Version = "v1" + }); + o.DocInclusionPredicate((docName, description) => true); + o.CustomSchemaIds(type => type.FullName); + o.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "Bearer", Type = ReferenceType.SecurityScheme + } + }, + Array.Empty() + } + }); + o.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = "请输入文字“Bearer”,后跟空格和JWT值,格式 : Bearer {token}", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey + }); + }); + } + + public override void OnApplicationShutdown(IApplicationBuilder app) + { + UseSwagger(app); + UseCors(app); + } + + private void UseSwagger(IApplicationBuilder app) + { + var env = app.ApplicationServices.GetService(); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(options => + { + options.SwaggerEndpoint("/swagger/v1/swagger.json", "API"); + options.RoutePrefix = string.Empty; + }); + } + } + + private void UseCors(IApplicationBuilder app) + { + app.UseCors(Constant.Cors); + } +} \ No newline at end of file diff --git a/test/NetCoreTest/Controllers/DemoController.cs b/test/NetCoreTest/Controllers/DemoController.cs index 6c8953ecfd6e6ebff648794ba6d660e18feadaf0..f66616259e53b9b51e3518af725cc5a81a62ae3b 100644 --- a/test/NetCoreTest/Controllers/DemoController.cs +++ b/test/NetCoreTest/Controllers/DemoController.cs @@ -1,9 +1,23 @@ using Microsoft.AspNetCore.Mvc; +using NetCore.Application.Contracts.Services; namespace NetCoreTest.Controllers; [ApiController] +[Route("api/demo")] public class DemoController : ControllerBase { + private readonly IDemoService _demoService; + + public DemoController(IDemoService demoService) + { + _demoService = demoService; + } + + [HttpGet] + public async Task GetAsync() + { + return await _demoService.GetAsync(); + } } \ No newline at end of file diff --git a/test/NetCoreTest/NetCoreTest.csproj b/test/NetCoreTest/NetCoreTest.csproj index 76037a2d092e89fabbaf862084ff408443be5316..a978c9eae08679ce90ebe6cd2491ff6b67e74ba8 100644 --- a/test/NetCoreTest/NetCoreTest.csproj +++ b/test/NetCoreTest/NetCoreTest.csproj @@ -6,13 +6,10 @@ enable - - - - + diff --git a/test/NetCoreTest/NetCoreTestModule.cs b/test/NetCoreTest/NetCoreTestModule.cs index 5301041140ef92a3b69726c4da6b16f7861f4731..ff350211f1ee470d45f3b9ad17ce3ed76ea0063b 100644 --- a/test/NetCoreTest/NetCoreTestModule.cs +++ b/test/NetCoreTest/NetCoreTestModule.cs @@ -1,10 +1,13 @@ using Token.Module; using NetCore.Application; +using NetCore.HttpApi; using Token.Module.Attributes; namespace NetCoreTest; -[DependOn(typeof(NetCoreApplicationModule))] +[DependOn( + typeof(NetCoreHttpApiModule), + typeof(NetCoreApplicationModule))] public class NetCoreTestModule :TokenModule { public override void ConfigureServices(IServiceCollection services) diff --git a/test/NetCoreTest/Program.cs b/test/NetCoreTest/Program.cs index 414e61e5f36d74f3a516a3ba12f81d8c85d1311a..d68e3f1ed3ebf5459e1347db0dc910473bd8a355 100644 --- a/test/NetCoreTest/Program.cs +++ b/test/NetCoreTest/Program.cs @@ -3,9 +3,12 @@ using NetCoreTest; var builder = WebApplication.CreateBuilder(args); +builder.Services.AddControllers(); builder.Services.AddTagApplication(); var app = builder.Build(); app.InitializeApplication(); +app.MapControllers(); + app.Run(); \ No newline at end of file