Skip to content

Commit 11e96ab

Browse files
authored
Auto register auto generated IHostBuilder extension methods (#1794)
* Updating function executor generator to include auto generated attributes. Updated tests * Fixed function metadata provided source gen and added tests * Package version bump. * Bump SDK version * Updating msbuild targets file to incldue the new properties * Set default value if empty * Auto registration of worker SDK generated IHostBuilder extension methods. * Minor cleanup + release notes * Fixed tests to use the renamed attribute name * Setting default value of FunctionsAutoRegisterGeneratedFunctionsExecutor msbuild prop to "True". Removing version suffix from package versions. * Reverting version changes in csproj * Switching to using an interace for type discovery instead of attributes. * Minor cleanup * PR comment fixes.
1 parent d990958 commit 11e96ab

File tree

15 files changed

+436
-27
lines changed

15 files changed

+436
-27
lines changed

release_notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616

1717
- Add placeholder support for linux platform. (#1704)
1818
- Remove incorrect failure log during successful cancellation flow (#1797)
19+
- Auto register auto generated IHostBuilder extension methods. (#1794)

sdk/Sdk.Generators/Constants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ internal static class BuildProperties
1414
{
1515
internal const string EnableSourceGen = "build_property.FunctionsEnableMetadataSourceGen";
1616
internal const string EnablePlaceholder = "build_property.FunctionsEnableExecutorSourceGen";
17+
internal const string AutoRegisterGeneratedFunctionsExecutor = "build_property.FunctionsAutoRegisterGeneratedFunctionsExecutor";
18+
internal const string AutoRegisterGeneratedMetadataProvider = "build_property.FunctionsAutoRegisterGeneratedMetadataProvider";
1719
}
1820

1921
internal static class FileNames

sdk/Sdk.Generators/FunctionExecutor/FunctionExecutorGenerator.Emitter.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ public partial class FunctionExecutorGenerator
1313
{
1414
internal static class Emitter
1515
{
16-
internal static string Emit(IEnumerable<ExecutableFunction> functions, CancellationToken cancellationToken)
16+
internal static string Emit(IEnumerable<ExecutableFunction> functions, bool includeAutoRegistrationCode, CancellationToken cancellationToken)
1717
{
18+
1819
string result = $$"""
1920
// <auto-generated/>
2021
using System;
@@ -52,7 +53,7 @@ public static IHostBuilder ConfigureGeneratedFunctionExecutor(this IHostBuilder
5253
s.AddSingleton<IFunctionExecutor, DirectFunctionExecutor>();
5354
});
5455
}
55-
}
56+
}{{GetAutoConfigureStartupClass(includeAutoRegistrationCode)}}
5657
}
5758
""";
5859

@@ -78,6 +79,26 @@ private static string GetTypesDictionary(IEnumerable<ExecutableFunction> functio
7879
""";
7980
}
8081

82+
private static string GetAutoConfigureStartupClass(bool includeAutoRegistrationCode)
83+
{
84+
if (includeAutoRegistrationCode)
85+
{
86+
string result = $$"""
87+
88+
public class FunctionExecutorAutoStartup : IAutoConfigureStartup
89+
{
90+
public void Configure(IHostBuilder hostBuilder)
91+
{
92+
hostBuilder.ConfigureGeneratedFunctionExecutor();
93+
}
94+
}
95+
""";
96+
97+
return result;
98+
}
99+
return "";
100+
}
101+
81102
private static string GetMethodBody(IEnumerable<ExecutableFunction> functions)
82103
{
83104
var sb = new StringBuilder();

sdk/Sdk.Generators/FunctionExecutor/FunctionExecutorGenerator.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,24 @@ public void Execute(GeneratorExecutionContext context)
3535
{
3636
return;
3737
}
38-
39-
var text = Emitter.Emit(functions, context.CancellationToken);
38+
39+
var shouldIncludeAutoGeneratedAttributes = ShouldIncludeAutoGeneratedAttributes(context);
40+
41+
var text = Emitter.Emit(functions, shouldIncludeAutoGeneratedAttributes, context.CancellationToken);
4042
context.AddSource(Constants.FileNames.GeneratedFunctionExecutor, SourceText.From(text, Encoding.UTF8));
4143
}
4244

45+
private static bool ShouldIncludeAutoGeneratedAttributes(GeneratorExecutionContext context)
46+
{
47+
if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(
48+
Constants.BuildProperties.AutoRegisterGeneratedFunctionsExecutor, out var value))
49+
{
50+
return false;
51+
}
52+
53+
return string.Equals(value, bool.TrueString, System.StringComparison.OrdinalIgnoreCase);
54+
}
55+
4356
private static bool ShouldExecuteGeneration(GeneratorExecutionContext context)
4457
{
4558
if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(

sdk/Sdk.Generators/FunctionMetadataProviderGenerator/FunctionMetadataProviderGenerator.Emitter.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4-
using System;
54
using System.Collections.Generic;
65
using System.Text;
76
using System.Text.Json;
@@ -19,7 +18,7 @@ internal sealed class Emitter
1918
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
2019
};
2120

22-
public string Emit(IReadOnlyList<GeneratorFunctionMetadata> funcMetadata, CancellationToken cancellationToken)
21+
public string Emit(IReadOnlyList<GeneratorFunctionMetadata> funcMetadata, bool includeAutoRegistrationCode, CancellationToken cancellationToken)
2322
{
2423
string functionMetadataInfo = AddFunctionMetadataInfo(funcMetadata, cancellationToken);
2524

@@ -60,11 +59,30 @@ public static IHostBuilder ConfigureGeneratedFunctionMetadataProvider(this IHost
6059
});
6160
return builder;
6261
}
63-
}
62+
}{{GetAutoConfigureStartupClass(includeAutoRegistrationCode)}}
6463
}
6564
""";
6665
}
6766

67+
private static string GetAutoConfigureStartupClass(bool includeAutoRegistrationCode)
68+
{
69+
if (includeAutoRegistrationCode)
70+
{
71+
string result = $$"""
72+
73+
public class FunctionMetadataProviderAutoStartup : IAutoConfigureStartup
74+
{
75+
public void Configure(IHostBuilder hostBuilder)
76+
{
77+
hostBuilder.ConfigureGeneratedFunctionMetadataProvider();
78+
}
79+
}
80+
""";
81+
82+
return result;
83+
}
84+
return "";
85+
}
6886
private string AddFunctionMetadataInfo(IReadOnlyList<GeneratorFunctionMetadata> functionMetadata, CancellationToken cancellationToken)
6987
{
7088
var functionCount = 0;

sdk/Sdk.Generators/FunctionMetadataProviderGenerator/FunctionMetadataProviderGenerator.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ public void Execute(GeneratorExecutionContext context)
4141
if (functionMetadataInfo.Count > 0)
4242
{
4343
Emitter e = new();
44-
string result = e.Emit(functionMetadataInfo, context.CancellationToken);
44+
var shouldIncludeAutoGeneratedAttributes = ShouldIncludeAutoGeneratedAttributes(context);
45+
46+
string result = e.Emit(functionMetadataInfo, shouldIncludeAutoGeneratedAttributes, context.CancellationToken);
4547

4648
context.AddSource(Constants.FileNames.GeneratedFunctionMetadata, SourceText.From(result, Encoding.UTF8));
4749
}
@@ -55,5 +57,16 @@ public void Initialize(GeneratorInitializationContext context)
5557
{
5658
context.RegisterForSyntaxNotifications(() => new FunctionMethodSyntaxReceiver());
5759
}
60+
61+
private static bool ShouldIncludeAutoGeneratedAttributes(GeneratorExecutionContext context)
62+
{
63+
if (!context.AnalyzerConfigOptions.GlobalOptions.TryGetValue(
64+
Constants.BuildProperties.AutoRegisterGeneratedMetadataProvider, out var value))
65+
{
66+
return false;
67+
}
68+
69+
return string.Equals(value, bool.TrueString, System.StringComparison.OrdinalIgnoreCase);
70+
}
5871
}
5972
}

sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
2323
<ItemGroup>
2424
<CompilerVisibleProperty Include="FunctionsEnableMetadataSourceGen" />
2525
<CompilerVisibleProperty Include="FunctionsEnableExecutorSourceGen" />
26+
<CompilerVisibleProperty Include="FunctionsAutoRegisterGeneratedFunctionsExecutor" />
27+
<CompilerVisibleProperty Include="FunctionsAutoRegisterGeneratedMetadataProvider" />
2628
</ItemGroup>
2729
<!--
2830
***********************************************************************************************

sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
3939
<FunctionsEnableWorkerIndexing Condition="$(FunctionsEnableWorkerIndexing) == '' And !$(FunctionsEnablePlaceholder)">false</FunctionsEnableWorkerIndexing>
4040
<FunctionsEnableMetadataSourceGen Condition="$(FunctionsEnableWorkerIndexing) And $(FunctionsEnableMetadataSourceGen) == ''">true</FunctionsEnableMetadataSourceGen>
4141
<FunctionsEnableExecutorSourceGen Condition="$(FunctionsEnableExecutorSourceGen) == ''">false</FunctionsEnableExecutorSourceGen>
42+
<FunctionsAutoRegisterGeneratedFunctionsExecutor Condition="$(FunctionsAutoRegisterGeneratedFunctionsExecutor) == ''">true</FunctionsAutoRegisterGeneratedFunctionsExecutor>
43+
<FunctionsAutoRegisterGeneratedFunctionsExecutor Condition="$(FunctionsAutoRegisterGeneratedFunctionsExecutor)">true</FunctionsAutoRegisterGeneratedFunctionsExecutor>
44+
<FunctionsAutoRegisterGeneratedMetadataProvider Condition="$(FunctionsAutoRegisterGeneratedMetadataProvider) == ''">false</FunctionsAutoRegisterGeneratedMetadataProvider>
45+
<FunctionsAutoRegisterGeneratedMetadataProvider Condition="$(FunctionsAutoRegisterGeneratedMetadataProvider)">true</FunctionsAutoRegisterGeneratedMetadataProvider>
4246
</PropertyGroup>
4347

4448
<UsingTask TaskName="GenerateFunctionMetadata"

sdk/release_notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414

1515
### Microsoft.Azure.Functions.Worker.Sdk.Generators <version>
1616

17-
- <entry>
17+
- Include _auto generated code_ attributes to `IHostBuilder` extension methods generated by functions worker SDK. (#1794)

src/DotNetWorker.Core/Hosting/CoreWorkerHostBuilderExtensions.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Linq;
6+
using System.Reflection;
57
using Microsoft.Azure.Functions.Worker;
68
using Microsoft.Extensions.DependencyInjection;
79

@@ -38,5 +40,29 @@ public static IHostBuilder ConfigureFunctionsWorker(this IHostBuilder builder, A
3840

3941
return builder;
4042
}
43+
44+
/// <summary>
45+
/// Invokes auto-generated configuration methods for a given <see cref="IHostBuilder"/>.
46+
/// This method searches for classes that implement the <see cref="IAutoConfigureStartup"/> interface,
47+
/// excluding interfaces and abstract classes. For each identified class, it locates the
48+
/// <c>Configure</c> method with the signature <c>void Configure(IHostBuilder hostBuilder)</c>,
49+
/// and executes the method using an instance of the class.
50+
/// </summary>
51+
/// <param name="builder">The <see cref="IHostBuilder"/> to configure.</param>
52+
/// <returns>The same <see cref="IHostBuilder"/> after the auto-generated configuration methods are invoked.</returns>
53+
public static IHostBuilder InvokeAutoGeneratedConfigureMethods(this IHostBuilder builder)
54+
{
55+
var autoConfigureStartupTypes = Assembly.GetEntryAssembly()!
56+
.GetTypes()
57+
.Where(t => typeof(IAutoConfigureStartup).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);
58+
59+
foreach (var type in autoConfigureStartupTypes)
60+
{
61+
var instance = (IAutoConfigureStartup)Activator.CreateInstance(type)!;
62+
instance.Configure(builder);
63+
}
64+
65+
return builder;
66+
}
4167
}
4268
}

0 commit comments

Comments
 (0)