From 1903486e04c9abbc563ab4bd04951719f3cb1d8a Mon Sep 17 00:00:00 2001 From: MarvelTiter Date: Fri, 22 May 2026 16:49:19 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A4=87=E4=BB=BD=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoInjectContextGeneratorHelpers.cs | 2 +- src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs | 11 +++++++++-- .../AutoInjectModuleGenerator.cs | 15 ++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs b/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs index 7057cb1..90fa989 100644 --- a/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs +++ b/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs @@ -386,7 +386,7 @@ public static AutoInjectInfo CollectCustomInject(INamedTypeSymbol classSymbol, S static bool CheckFirstParameter(IMethodSymbol method) { - if (method.Parameters.Length > 0 && method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.DependencyInjection.IServiceCollection") + if (method.Parameters.Length > 0 && (method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.DependencyInjection.IServiceCollection" || method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.Hosting.IHostApplicationBuilder")) { return true; } diff --git a/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs b/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs index 1f86b70..ab9d698 100644 --- a/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs +++ b/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs @@ -11,6 +11,7 @@ namespace AutoInjectGenerator; [Generator(LanguageNames.CSharp)] public class AutoInjectEntryGenerator : IIncrementalGenerator { + public static bool IsHostApplicationBuilder { get; set; } public void Initialize(IncrementalGeneratorInitializationContext context) { var value = context.SyntaxProvider.ForAttributeWithMetadataName(AutoInjectContext @@ -53,8 +54,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .AddGeneratedCodeAttribute(typeof(AutoInjectContextGenerator)) .Modifiers("static partial"); - var serviceName = methodSymbol.Parameters.First(p => - p.Type.ToDisplayString().Contains("Microsoft.Extensions.DependencyInjection.IServiceCollection")).Name; + var serviceName = methodSymbol.Parameters.FirstOrDefault(p => + p.Type.ToDisplayString().Contains("Microsoft.Extensions.DependencyInjection.IServiceCollection"))?.Name; + + if (serviceName is null) + { + serviceName = methodSymbol.Parameters.FirstOrDefault(p => p.Type.ToDisplayString().Contains("Microsoft.Extensions.Hosting.IHostApplicationBuilder"))?.Name; + IsHostApplicationBuilder = true; + } var includeField = FieldBuilder.Default .Modifiers("private static readonly") diff --git a/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs b/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs index bf48906..a6940b5 100644 --- a/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs +++ b/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs @@ -71,7 +71,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Attribute(AutoInjectModule) .AddGeneratedCodeAttribute(typeof(AutoInjectModuleGenerator)); - gclass.AddMembers([.. InitMethods(asm, services)]); + gclass.AddMembers([.. InitMethods(services)]); return CodeFile.New($"{asm.SafeMetaName()}.AutoInject.ModuleServices.g.cs").AddUsings("using Microsoft.Extensions.DependencyInjection;") .AddUsings("using Microsoft.Extensions.DependencyInjection.Extensions;") .AddUsings("using AutoInjectGenerator.Models;") @@ -80,10 +80,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context) } const string SD = "AutoInjectServiceDescriptor"; - private static IEnumerable InitMethods(IAssemblySymbol asm, ImmutableArray services) + private static IEnumerable InitMethods(ImmutableArray services) { // global::System.Runtime.CompilerServices.ModuleInitializerAttribute - var serviceName = "services"; + var parameterName = AutoInjectEntryGenerator.IsHostApplicationBuilder ? "builder":"services"; + var serviceName = AutoInjectEntryGenerator.IsHostApplicationBuilder ? "builder.Services" : "services"; var configName = "config"; var body = new List(); List customs = []; @@ -128,17 +129,17 @@ private static IEnumerable InitMethods(IAssemblySymbol asm, Immut body.Add("// 调用自定义配置服务"); if (info.CustomInjectInfo!.ParameterCount == 1) { - body.Add($"global::{info.TargetSymbol.ToDisplayString()}.{info.CustomInjectInfo.MethodName}({serviceName})"); + body.Add($"global::{info.TargetSymbol.ToDisplayString()}.{info.CustomInjectInfo.MethodName}({parameterName})"); } else if (info.CustomInjectInfo.ParameterCount == 2) { - body.Add($"global::{info.TargetSymbol.ToDisplayString()}.{info.CustomInjectInfo.MethodName}({serviceName}, {configName})"); + body.Add($"global::{info.TargetSymbol.ToDisplayString()}.{info.CustomInjectInfo.MethodName}({parameterName}, {configName})"); } } - + var sp = AutoInjectEntryGenerator.IsHostApplicationBuilder ? "global::Microsoft.Extensions.Hosting.IHostApplicationBuilder builder": "IServiceCollection services"; yield return MethodBuilder.Default.MethodName("InjectModuleServices") .Modifiers("public static") - .AddParameter("IServiceCollection services", "AutoInjectConfiguration config") + .AddParameter(sp, "AutoInjectConfiguration config") .AddGeneratedCodeAttribute(typeof(AutoInjectModuleGenerator)) .AddBody([.. body]); From 44ff355e861cacb16ae5a36495e14e914607ef7c Mon Sep 17 00:00:00 2001 From: MarvelTiter_yaoqinglin Date: Fri, 22 May 2026 22:24:27 +0800 Subject: [PATCH 2/2] 1 --- ...10\346\234\254\346\227\245\345\277\227.md" | 1 + .../AutoInjectContextGeneratorHelpers.cs | 123 +++++++++--------- .../AutoInjectContextInfo.cs | 5 +- .../AutoInjectEntryGenerator.cs | 64 +++++++-- src/AutoInject.Roslyn/AutoInjectInfo.cs | 2 +- .../AutoInjectModuleGenerator.cs | 47 ++++--- .../DiagnosticDefinitions.cs | 13 ++ ...stomModuleServiceConfigurationAttribute.cs | 2 +- src/AutoInjectGenerator/Versions.props | 2 +- src/AutoInjectGenerator/readme.md | 6 + .../Blazor.Test/AutoInjectContext.cs | 8 +- src/Blazor.Test/Blazor.Test/Program.cs | 8 +- src/InjectTest/InjectTest.csproj | 6 +- src/InjectTest/InjectTestClass.cs | 5 +- 14 files changed, 187 insertions(+), 105 deletions(-) diff --git "a/doc/AutoInject\347\211\210\346\234\254\346\227\245\345\277\227.md" "b/doc/AutoInject\347\211\210\346\234\254\346\227\245\345\277\227.md" index df15197..40f0ac3 100644 --- "a/doc/AutoInject\347\211\210\346\234\254\346\227\245\345\277\227.md" +++ "b/doc/AutoInject\347\211\210\346\234\254\346\227\245\345\277\227.md" @@ -2,6 +2,7 @@ ## v2026.05.22 - ⚡️新增`CustomModuleServiceConfigurationAttribute`,用于提供给`AutoInjectModuleGenerator`生成项目注入代码时,调用额外的服务注入 +- ⚡️改进注入方法,现在可以使用`IHostApplicationBuilder`代替`IServiceCollection`作为参数, 如果子模式使用了`IHostApplicationBuilder`, 总入口必须使用`IHostApplicationBuilder` ## v2026.05.20 - ⚡️现在可以通过`AutoInjectAttribute`的`Factory`,`Instance`,`DeclaredType`等属性配置工厂模式或者实例的注入 diff --git a/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs b/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs index 90fa989..edf1c8f 100644 --- a/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs +++ b/src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs @@ -54,7 +54,7 @@ public static AutoInjectContextInfo CollectContextInfo(GeneratorAttributeSyntaxC { var classSymbol = (INamedTypeSymbol)context.TargetSymbol; //context.TargetSymbol.GetAttribute(AutoInjectContext, out var contextAttr); - var ctxInfo = new AutoInjectContextInfo(classSymbol); + var ctxInfo = new AutoInjectContextInfo(classSymbol, context.TargetNode); if (classSymbol.GetMembers().FirstOrDefault(m => m is IMethodSymbol { IsPartialDefinition: true, PartialImplementationPart: null, IsStatic: true @@ -64,6 +64,7 @@ public static AutoInjectContextInfo CollectContextInfo(GeneratorAttributeSyntaxC return ctxInfo; } ctxInfo.MethodSymbol = methodSymbol; + ctxInfo.IsHostBuilder = methodSymbol.Parameters.Any(p => p.Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting")); var allConfig = methodSymbol.GetAttributes(AutoInjectConfiguration).Select(c => { var i = c.GetNamedValue("Include")?.ToString() ?? ""; @@ -86,37 +87,37 @@ public static AutoInjectContextInfo CollectContextInfo(GeneratorAttributeSyntaxC return ctxInfo; } - public static AutoInjectContextInfo CollectContextInfo(GeneratorSyntaxCollectInfoContext context) - { - var classSymbol = (INamedTypeSymbol)context.TargetSymbol; - var ctxInfo = new AutoInjectContextInfo(classSymbol); - if (classSymbol.GetMembers().FirstOrDefault(m => m is IMethodSymbol - { - IsPartialDefinition: true, PartialImplementationPart: null, IsStatic: true - }) is not IMethodSymbol methodSymbol) - { - ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00001(context.GetDiagnosticLocation()); - return ctxInfo; - } - ctxInfo.MethodSymbol = methodSymbol; - var allConfig = methodSymbol.GetAttributes(AutoInjectConfiguration).Select(c => - { - var i = c.GetNamedValue("Include")?.ToString() ?? ""; - var e = c.GetNamedValue("Exclude")?.ToString() ?? ""; - return (i, e); - }).ToArray(); + //public static AutoInjectContextInfo CollectContextInfo(GeneratorSyntaxCollectInfoContext context) + //{ + // var classSymbol = (INamedTypeSymbol)context.TargetSymbol; + // var ctxInfo = new AutoInjectContextInfo(classSymbol); + // if (classSymbol.GetMembers().FirstOrDefault(m => m is IMethodSymbol + // { + // IsPartialDefinition: true, PartialImplementationPart: null, IsStatic: true + // }) is not IMethodSymbol methodSymbol) + // { + // ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00001(context.GetDiagnosticLocation()); + // return ctxInfo; + // } + // ctxInfo.MethodSymbol = methodSymbol; + // var allConfig = methodSymbol.GetAttributes(AutoInjectConfiguration).Select(c => + // { + // var i = c.GetNamedValue("Include")?.ToString() ?? ""; + // var e = c.GetNamedValue("Exclude")?.ToString() ?? ""; + // return (i, e); + // }).ToArray(); - ctxInfo.Includes = [.. allConfig.Select(t => t.i).Where(s => !string.IsNullOrEmpty(s))]; + // ctxInfo.Includes = [.. allConfig.Select(t => t.i).Where(s => !string.IsNullOrEmpty(s))]; - ctxInfo.Excludes = [.. allConfig.Select(t => t.e).Where(s => !string.IsNullOrEmpty(s))]; - if (ctxInfo.Includes.Intersect(ctxInfo.Excludes).Any()) - { - var methodLocation = methodSymbol.TryGetLocation(); - ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00002(methodLocation); - return ctxInfo; - } - return ctxInfo; - } + // ctxInfo.Excludes = [.. allConfig.Select(t => t.e).Where(s => !string.IsNullOrEmpty(s))]; + // if (ctxInfo.Includes.Intersect(ctxInfo.Excludes).Any()) + // { + // var methodLocation = methodSymbol.TryGetLocation(); + // ctxInfo.Diagnostic = DiagnosticDefinitions.AIG00002(methodLocation); + // return ctxInfo; + // } + // return ctxInfo; + //} //public static AutoInjectInfo CollectInjectInfo(GeneratorSyntaxCollectInfoContext context) //{ @@ -340,55 +341,47 @@ AutoInjectInfo BuildFormManualInjectConfig(AttributeData a) } } - public static AutoInjectInfo CollectCustomInject(INamedTypeSymbol classSymbol, SyntaxNode targetNode) + public static AutoInjectInfo CollectCustomInject(IMethodSymbol methodSymbol, SyntaxNode targetNode) { + var classSymbol = methodSymbol.ContainingType; var info = new AutoInjectInfo(classSymbol) { CustomInject = true, }; - var methods = classSymbol.GetMethods(m => m.IsStatic); - IMethodSymbol? best = null; - foreach (var method in methods) + if (methodSymbol.Parameters.Length > 2) { - if (method.Parameters.Length > 2) - { - info.Diagnostic = DiagnosticDefinitions.AIG00008(targetNode.GetLocation()); - return info; - } - if (!CheckFirstParameter(method)) - { - info.Diagnostic = DiagnosticDefinitions.AIG00009(targetNode.GetLocation()); - return info; - } - best ??= method; - var p2check = CheckSecondParameter(method); - if (p2check.HasValue) - { - if (p2check.Value) - { - best = method; - break; - } - else - { - info.Diagnostic = DiagnosticDefinitions.AIG00010(targetNode.GetLocation()); - return info; - } - } + info.Diagnostic = DiagnosticDefinitions.AIG00008(targetNode.GetLocation()); + return info; } - if (best is null) + if (!CheckFirstParameter(methodSymbol, out bool isHostBuilder)) { - info.Diagnostic = DiagnosticDefinitions.AIG00011(targetNode.GetLocation()); + info.Diagnostic = DiagnosticDefinitions.AIG00009(targetNode.GetLocation()); return info; } - info.CustomInjectInfo = new CustomInjectInfo(best.Parameters.Length, best.Name); + var p2check = CheckSecondParameter(methodSymbol); + if (p2check.HasValue) + { + if (!p2check.Value) + { + info.Diagnostic = DiagnosticDefinitions.AIG00010(targetNode.GetLocation()); + return info; + } + } + info.CustomInjectInfo = new CustomInjectInfo(methodSymbol.Parameters.Length, methodSymbol.Name, isHostBuilder); return info; - static bool CheckFirstParameter(IMethodSymbol method) + static bool CheckFirstParameter(IMethodSymbol method, out bool isHostBuilder) { - if (method.Parameters.Length > 0 && (method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.DependencyInjection.IServiceCollection" || method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.Hosting.IHostApplicationBuilder")) + isHostBuilder = false; + if (method.Parameters.Length > 0) { - return true; + if (method.Parameters[0].Type.ToDisplayString() == "Microsoft.Extensions.DependencyInjection.IServiceCollection") + return true; + if (method.Parameters[0].Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting")) // Microsoft.Extensions.Hosting.IHostApplicationBuilder + { + isHostBuilder = true; + return true; + } } return false; } diff --git a/src/AutoInject.Roslyn/AutoInjectContextInfo.cs b/src/AutoInject.Roslyn/AutoInjectContextInfo.cs index 518b19c..334a08b 100644 --- a/src/AutoInject.Roslyn/AutoInjectContextInfo.cs +++ b/src/AutoInject.Roslyn/AutoInjectContextInfo.cs @@ -2,11 +2,14 @@ namespace AutoInjectGenerator; -public class AutoInjectContextInfo(INamedTypeSymbol targetSymbol) +public class AutoInjectContextInfo(INamedTypeSymbol targetSymbol, SyntaxNode node) { public INamedTypeSymbol TargetSymbol { get; } = targetSymbol; + public SyntaxNode Node { get; } = node; + public string ClassName => TargetSymbol.MetadataName; public IMethodSymbol? MethodSymbol { get; set; } + public bool IsHostBuilder { get; set; } public string[] Includes { get; set; } = []; public string[] Excludes { get; set; } = []; public bool? ContainSelf { get; set; } diff --git a/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs b/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs index ab9d698..1b35d7b 100644 --- a/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs +++ b/src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using static AutoInjectGenerator.AutoInjectContextGeneratorHelpers; @@ -11,7 +12,6 @@ namespace AutoInjectGenerator; [Generator(LanguageNames.CSharp)] public class AutoInjectEntryGenerator : IIncrementalGenerator { - public static bool IsHostApplicationBuilder { get; set; } public void Initialize(IncrementalGeneratorInitializationContext context) { var value = context.SyntaxProvider.ForAttributeWithMetadataName(AutoInjectContext @@ -21,7 +21,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { var target = source.TargetSymbol; var asm = target.ContainingAssembly; - var modules = new List(); + var modules = new List<(INamedTypeSymbol, bool)>(); source.ContainSelf = asm.GlobalNamespace?.GetAllMembers(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInject, true)).Any(); foreach (var item in asm.Modules) @@ -32,7 +32,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context) continue; if (referencedAssembly.GlobalNamespace is null) continue; - modules.AddRange(referencedAssembly.GlobalNamespace.GetAllMembers(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInjectModule))); + + var moduleInit = referencedAssembly.GlobalNamespace.GetAllMembers(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInjectModule)).FirstOrDefault(); + if (moduleInit is null) + continue; + var customInject = referencedAssembly.GlobalNamespace.GetAllMembers(i => i is IMethodSymbol m && m.HasAttribute(CustomInject)); + bool isHostBuilder = false; + foreach (var cc in customInject) + { + if (cc.Parameters.Any(p => p.Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting"))) + { + isHostBuilder = true; + if (!source.IsHostBuilder) + { + spc.ReportDiagnostic(DiagnosticDefinitions.AIG00012(source.Node.GetLocation())); + return; + } + break; + } + } + modules.Add((moduleInit, isHostBuilder)); } } var file = CreateCodeFile(source, modules); @@ -43,7 +62,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) }); } - private static CodeFile? CreateCodeFile(AutoInjectContextInfo context, List modules) + private static CodeFile? CreateCodeFile(AutoInjectContextInfo context, List<(INamedTypeSymbol, bool)> modules) { var classSymbol = context.TargetSymbol; var className = context.ClassName; @@ -59,8 +78,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) if (serviceName is null) { - serviceName = methodSymbol.Parameters.FirstOrDefault(p => p.Type.ToDisplayString().Contains("Microsoft.Extensions.Hosting.IHostApplicationBuilder"))?.Name; - IsHostApplicationBuilder = true; + serviceName = methodSymbol.Parameters.FirstOrDefault(p => p.Type.ToDisplayString().StartsWith("Microsoft.Extensions.Hosting"))?.Name; + context.IsHostBuilder = true; } var includeField = FieldBuilder.Default @@ -75,22 +94,46 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .InitializeWith($"[{string.Join(", ", context.Excludes.Select(s => $"\"{s}\""))}] "); var cm = MethodBuilder.Default.Partial(methodSymbol); - { - // 创建配置 + + {// 创建配置 List methodBody = [ "var config = new global::AutoInjectGenerator.AutoInjectConfiguration(_excludes, _includes)", //$"global::AutoInjectGenerator.AutoInjectManager.ApplyProjectServices({serviceName}, config)" ]; if (context.ContainSelf == true) { - methodBody.Add($"global::{context.TargetSymbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)"); + if (context.IsHostBuilder) + { + methodBody.Add($"global::{context.TargetSymbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}.Services, config)"); + } + else + { + methodBody.Add($"global::{context.TargetSymbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)"); + } } foreach (var item in modules) { - methodBody.Add($"global::{item.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)"); + var symbol = item.Item1; + var isHostBuilder = item.Item2; + if (isHostBuilder) + { + methodBody.Add($"global::{symbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)"); + } + else + { + if (context.IsHostBuilder) + { + methodBody.Add($"global::{symbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}.Services, config)"); + } + else + { + methodBody.Add($"global::{symbol.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)"); + } + } } cm.AddBody([.. methodBody]); } + gclass.AddMembers(includeField); gclass.AddMembers(excludeField); gclass.AddMembers(cm); @@ -107,3 +150,4 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return file; } } + diff --git a/src/AutoInject.Roslyn/AutoInjectInfo.cs b/src/AutoInject.Roslyn/AutoInjectInfo.cs index 31b45e3..c5b9943 100644 --- a/src/AutoInject.Roslyn/AutoInjectInfo.cs +++ b/src/AutoInject.Roslyn/AutoInjectInfo.cs @@ -16,7 +16,7 @@ public class AutoInjectInfo(INamedTypeSymbol targetSymbol) //public string? MemberShip { get; set; } } -public record CustomInjectInfo(int ParameterCount, string MethodName); +public record CustomInjectInfo(int ParameterCount, string MethodName, bool IsHostBuilder); public record RegisterServiceInfo(string Scoped, string ServiceType, string? Key, string? MemberShip, string? Factory, string? Instance, INamedTypeSymbol DeclaredType) { diff --git a/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs b/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs index a6940b5..7e99d9c 100644 --- a/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs +++ b/src/AutoInject.Roslyn/AutoInjectModuleGenerator.cs @@ -19,7 +19,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // , static (node, _) => node is ClassDeclarationSyntax // , static (ctx, _) => CollectInjectInfo(ctx)).Collect(); - var targets = context.SyntaxProvider.CreateSyntaxProvider( + var clas = context.SyntaxProvider.CreateSyntaxProvider( static (node, _) => node is ClassDeclarationSyntax cs && cs.AttributeLists.Count > 0, static (ctx, _) => { @@ -30,12 +30,20 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { return CollectInjectInfo(classSymbol, ctx.Node); } - else if (classSymbol.HasAttribute(CustomInject)) - { - return CollectCustomInject(classSymbol, ctx.Node); - } - return null; + return null!; }).Where(static i => i is not null)!.Collect(); + + var mes = context.SyntaxProvider.ForAttributeWithMetadataName(CustomInject, + static (node, _) => node is MethodDeclarationSyntax cs && cs.AttributeLists.Count > 0, + static (ctx, _) => CollectCustomInject((IMethodSymbol)ctx.TargetSymbol, ctx.TargetNode)).Collect(); + + var targets = clas.Combine(mes).Select((tuple, _) => + { + var c = tuple.Left; + var m = tuple.Right; + return c.AddRange(m); + }); + context.RegisterSourceOutput(context.CompilationProvider.Combine(targets), static (spc, source) => { var (compilation, services) = source; @@ -83,18 +91,18 @@ public void Initialize(IncrementalGeneratorInitializationContext context) private static IEnumerable InitMethods(ImmutableArray services) { // global::System.Runtime.CompilerServices.ModuleInitializerAttribute - var parameterName = AutoInjectEntryGenerator.IsHostApplicationBuilder ? "builder":"services"; - var serviceName = AutoInjectEntryGenerator.IsHostApplicationBuilder ? "builder.Services" : "services"; var configName = "config"; var body = new List(); - List customs = []; - foreach (var info in services) + List customs = [.. services.Where(s => s.CustomInject && s.CustomInjectInfo is not null)]; + List autos = [.. services.Where(s => !s.CustomInject)]; + + var isBuilder = customs.Any(a => a.CustomInjectInfo!.IsHostBuilder); + + var parameterName = isBuilder ? "builder" : "services"; + var serviceName = isBuilder ? "builder.Services" : "services"; + + foreach (var info in autos) { - if (info.CustomInject && info.CustomInjectInfo is not null) - { - customs.Add(info); - continue; - } if (info is null || info.Services.Count == 0) { body.Add($"// No services to register for {info?.Implement}"); @@ -126,17 +134,18 @@ private static IEnumerable InitMethods(ImmutableArray Diagnostic.Create(new D defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true), location); + /// + /// 子模块使用了IHostApplicationBuilder作为参数 + /// + /// + /// + public static Diagnostic AIG00012(Location? location) => Diagnostic.Create(new DiagnosticDescriptor( + id: "AIG00012", + title: "子模块使用了IHostApplicationBuilder作为参数", + messageFormat: "子模块使用了IHostApplicationBuilder作为参数", + category: typeof(AutoInjectContextGenerator).FullName!, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true), location); + } } diff --git a/src/AutoInjectGenerator/Attributes/CustomModuleServiceConfigurationAttribute.cs b/src/AutoInjectGenerator/Attributes/CustomModuleServiceConfigurationAttribute.cs index e8b88aa..e0f3c41 100644 --- a/src/AutoInjectGenerator/Attributes/CustomModuleServiceConfigurationAttribute.cs +++ b/src/AutoInjectGenerator/Attributes/CustomModuleServiceConfigurationAttribute.cs @@ -7,7 +7,7 @@ namespace AutoInjectGenerator; /// /// 为当前项目配置专属的服务注册时使用 /// -[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class CustomModuleServiceConfigurationAttribute : Attribute { } diff --git a/src/AutoInjectGenerator/Versions.props b/src/AutoInjectGenerator/Versions.props index d98f3b9..0dcd5dd 100644 --- a/src/AutoInjectGenerator/Versions.props +++ b/src/AutoInjectGenerator/Versions.props @@ -1,6 +1,6 @@  - 2026.05.22.1 + 2026.05.22.2 $(BuildVersion) $(BuildVersion) diff --git a/src/AutoInjectGenerator/readme.md b/src/AutoInjectGenerator/readme.md index 81ce4c2..bca6de9 100644 --- a/src/AutoInjectGenerator/readme.md +++ b/src/AutoInjectGenerator/readme.md @@ -85,6 +85,12 @@ static partial class AutoInjectContext 自己编写额外的服务方法提供给`InjectModuleServices`调用([详情](##生成逻辑梳理)) +#### CustomModuleServiceConfigurationAttribute高级用法 + +自定义的注入方法可以使用`IHostApplicationBuilder`作为参数。 + +例如,需要`IConfiguration`等等, 因此`AutoInjectContext`处的方法的参数需要提升为`IHostApplicationBuilder` + ### InjectLifeTime 可能的值 diff --git a/src/Blazor.Test/Blazor.Test/AutoInjectContext.cs b/src/Blazor.Test/Blazor.Test/AutoInjectContext.cs index e37de71..5f024c8 100644 --- a/src/Blazor.Test/Blazor.Test/AutoInjectContext.cs +++ b/src/Blazor.Test/Blazor.Test/AutoInjectContext.cs @@ -9,14 +9,18 @@ namespace Blazor.Test public static partial class AutoInjectContext { [AutoInjectConfiguration(Include = "SERVER")] - public static partial void Inject(this IServiceCollection services); + //public static partial void Inject(this IServiceCollection services); + public static partial void Inject(this IHostApplicationBuilder builder); + } [AutoInjectContext] public static partial class AutoInjectContextHybrid { [AutoInjectConfiguration(Include = "HYBRID")] - public static partial void InjectHybrid(this IServiceCollection services); + //public static partial void InjectHybrid(this IServiceCollection services); + public static partial void InjectHybrid(this IHostApplicationBuilder builder); + } } diff --git a/src/Blazor.Test/Blazor.Test/Program.cs b/src/Blazor.Test/Blazor.Test/Program.cs index 1ce4beb..0eb3f96 100644 --- a/src/Blazor.Test/Blazor.Test/Program.cs +++ b/src/Blazor.Test/Blazor.Test/Program.cs @@ -22,8 +22,12 @@ builder.Services.AddScoped(); builder.Host.UseServiceProviderFactory(new AutoAopProxyGenerator.AutoAopProxyServiceProviderFactory()); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); -builder.Services.Inject(); -builder.Services.InjectHybrid(); +//builder.Services.Inject(); +builder.Inject(); + +//builder.Services.InjectHybrid(); +builder.InjectHybrid(); + builder.Services.AddHttpClient(); builder.Services.AddStateContainers(); builder.Services.AddMapperService(o => diff --git a/src/InjectTest/InjectTest.csproj b/src/InjectTest/InjectTest.csproj index c3864c4..372f004 100644 --- a/src/InjectTest/InjectTest.csproj +++ b/src/InjectTest/InjectTest.csproj @@ -7,7 +7,11 @@ - + + + + + diff --git a/src/InjectTest/InjectTestClass.cs b/src/InjectTest/InjectTestClass.cs index 1fa3f5e..5dea0a9 100644 --- a/src/InjectTest/InjectTestClass.cs +++ b/src/InjectTest/InjectTestClass.cs @@ -2,6 +2,7 @@ using AutoInjectGenerator; using AutoWasmApiGenerator; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace InjectTest { @@ -79,10 +80,10 @@ public class ChildType : ParentType } - [CustomModuleServiceConfiguration] public class InjectConfig { - public static void AddService(IServiceCollection services, AutoInjectConfiguration config) + [CustomModuleServiceConfiguration] + public static void AddService(IServiceCollection builder, AutoInjectConfiguration config) { }