From 640bcee0a5f64e6d298ef4ab4367e52fbb3ae725 Mon Sep 17 00:00:00 2001 From: Marcos Junior Date: Thu, 19 May 2022 16:15:22 -0500 Subject: [PATCH] Fix local telemetry client dependency (#26) * Fix local telemetry client dependency * Bump sample to NET 6 * Add dotnet 6 build process --- .github/workflows/main.yml | 6 +- .vscode/extensions.json | 6 ++ .vscode/launch.json | 14 ++++ .vscode/settings.json | 7 ++ .vscode/tasks.json | 81 +++++++++++++++++++ ....DependencyInjection.AzureFunctions.csproj | 6 +- .../ConfigurationExtensions.cs | 29 ++++++- .../LoggerModule.cs | 3 + .../ScopedJobActivator.cs | 26 +++++- .../Scopes.cs | 8 +- SampleAutofacFunction/Functions/Function3.cs | 41 ++++++++++ .../SampleAutofacFunction.csproj | 16 ++-- 12 files changed, 225 insertions(+), 18 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 SampleAutofacFunction/Functions/Function3.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bb692cb..55239df 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,6 +24,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + + - uses: actions/setup-dotnet@v2 + with: + dotnet-version: '6.0.x' - name: "Get Commit Date" uses: actions/github-script@0.3.0 @@ -53,7 +57,7 @@ jobs: run: nuget restore - name: Build - run: msbuild -p:Configuration="$BUILD_CONFIGURATION" -p:Platform="$BUILD_PLATFORM" -m -p:GeneratePackageOnBuild=true -p:OutDir=$PUBLISH_DIR -p:Version=$VERSION_NUMBER -p:AssemblyVersion=$VERSION_NUMBER -p:AssemblyInformationalVersion=$VERSION_NUMBER -p:PackageVersion=$PACKAGE_VERSION -p:GenerateProjectSpecificOutputFolder=true + run: dotnet build -p:Configuration="$BUILD_CONFIGURATION" -p:Platform="$BUILD_PLATFORM" -m -p:GeneratePackageOnBuild=true -p:OutDir=$PUBLISH_DIR -p:Version=$VERSION_NUMBER -p:AssemblyVersion=$VERSION_NUMBER -p:AssemblyInformationalVersion=$VERSION_NUMBER -p:PackageVersion=$PACKAGE_VERSION -p:GenerateProjectSpecificOutputFolder=true - uses: actions/upload-artifact@v2 name: Upload artifact diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..de991f4 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-azuretools.vscode-azurefunctions", + "ms-dotnettools.csharp" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..200724b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to .NET Functions", + "type": "coreclr", + "request": "attach", + "processId": "${command:azureFunctions.pickProcess}" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c61e7dd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "azureFunctions.deploySubpath": "SampleAutofacFunction/bin/Release/netcoreapp3.1/publish", + "azureFunctions.projectLanguage": "C#", + "azureFunctions.projectRuntime": "~3", + "debug.internalConsoleOptions": "neverOpen", + "azureFunctions.preDeployTask": "publish (functions)" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..46543cd --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,81 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "clean (functions)", + "command": "dotnet", + "args": [ + "clean", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/SampleAutofacFunction" + } + }, + { + "label": "build (functions)", + "command": "dotnet", + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean (functions)", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/SampleAutofacFunction" + } + }, + { + "label": "clean release (functions)", + "command": "dotnet", + "args": [ + "clean", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/SampleAutofacFunction" + } + }, + { + "label": "publish (functions)", + "command": "dotnet", + "args": [ + "publish", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean release (functions)", + "problemMatcher": "$msCompile", + "options": { + "cwd": "${workspaceFolder}/SampleAutofacFunction" + } + }, + { + "type": "func", + "dependsOn": "build (functions)", + "options": { + "cwd": "${workspaceFolder}/SampleAutofacFunction/bin/Debug/netcoreapp3.1" + }, + "command": "host start", + "isBackground": true, + "problemMatcher": "$func-dotnet-watch" + } + ] +} \ No newline at end of file diff --git a/Autofac.Extensions.DependencyInjection.AzureFunctions/Autofac.Extensions.DependencyInjection.AzureFunctions.csproj b/Autofac.Extensions.DependencyInjection.AzureFunctions/Autofac.Extensions.DependencyInjection.AzureFunctions.csproj index eb95d44..bdf3c28 100644 --- a/Autofac.Extensions.DependencyInjection.AzureFunctions/Autofac.Extensions.DependencyInjection.AzureFunctions.csproj +++ b/Autofac.Extensions.DependencyInjection.AzureFunctions/Autofac.Extensions.DependencyInjection.AzureFunctions.csproj @@ -4,7 +4,7 @@ netstandard2.0 6.0.0 Autofac implementation of the dependency injection factory for Azure Functions. - Copyright © 2020 Marcos Almeida Jr + Copyright © 2022 Marcos Almeida Jr true true en-US @@ -26,11 +26,11 @@ Autofac true $(OutDir)/$(AssemblyName) - 6.0.0 + 7.2.0 - + diff --git a/Autofac.Extensions.DependencyInjection.AzureFunctions/ConfigurationExtensions.cs b/Autofac.Extensions.DependencyInjection.AzureFunctions/ConfigurationExtensions.cs index 1818b73..37630c3 100644 --- a/Autofac.Extensions.DependencyInjection.AzureFunctions/ConfigurationExtensions.cs +++ b/Autofac.Extensions.DependencyInjection.AzureFunctions/ConfigurationExtensions.cs @@ -1,8 +1,10 @@ using Microsoft.Azure.Functions.Extensions.DependencyInjection; using Microsoft.Azure.WebJobs.Host; +using Microsoft.Azure.WebJobs.Host.Executors; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using System; +using System.Linq; namespace Autofac.Extensions.DependencyInjection.AzureFunctions { @@ -11,6 +13,10 @@ namespace Autofac.Extensions.DependencyInjection.AzureFunctions /// public static class ConfigurationExtensions { + internal const string functionInstanceParam = "functionInstance"; + internal const string iEnvironmentParam = "iEnvironment"; + + internal static Type IEnvironmentType; /// /// Attatch the to the of the current function host. /// @@ -31,6 +37,27 @@ public static IFunctionsHostBuilder UseAutofacServiceProviderFactory(this IFunct // Call the user code to configure the container configurationAction?.Invoke(containerBuilder); + IEnvironmentType = hostBuilder.Services.Where(s => s.ServiceType.Namespace == "Microsoft.Azure.WebJobs.Script").FirstOrDefault()?.ServiceType.Assembly.GetExportedTypes().Where(x => x.Name == "IEnvironment").FirstOrDefault(); + if (IEnvironmentType != null) + { + containerBuilder.Register((r, p) => + { + var instance = p.Named(iEnvironmentParam); + return instance; + }).As(IEnvironmentType) + .ExternallyOwned() + .SingleInstance(); + } + + containerBuilder.Register((r, p) => + { + var instance = p.Named(functionInstanceParam); + return instance; + }) + .AsSelf() + .ExternallyOwned() + .InstancePerTriggerRequest(); + var container = containerBuilder.Build(); return new AutofacContainer(container); }); @@ -66,7 +93,7 @@ internal class ScopedContainer : IDisposable public ILifetimeScope Scope { get; } public ScopedContainer(AutofacContainer container) { - Scope = container.Container.BeginLifetimeScope(Scopes.RootLifetimeScopeTag); + Scope = container.Container.BeginLifetimeScope(Scopes.LifetimeScopeTag); } public void Dispose() diff --git a/Autofac.Extensions.DependencyInjection.AzureFunctions/LoggerModule.cs b/Autofac.Extensions.DependencyInjection.AzureFunctions/LoggerModule.cs index 28ed7c0..7068bdc 100644 --- a/Autofac.Extensions.DependencyInjection.AzureFunctions/LoggerModule.cs +++ b/Autofac.Extensions.DependencyInjection.AzureFunctions/LoggerModule.cs @@ -7,6 +7,7 @@ internal class LoggerModule : Module public const string functionNameParam = "functionName"; public const string loggerFactoryParam = "loggerFactory"; + protected override void Load(ContainerBuilder builder) { builder @@ -17,6 +18,7 @@ protected override void Load(ContainerBuilder builder) return factory; }) .AsSelf() + .ExternallyOwned() .SingleInstance(); builder @@ -30,6 +32,7 @@ protected override void Load(ContainerBuilder builder) .AsSelf() .InstancePerTriggerRequest(); + } } } \ No newline at end of file diff --git a/Autofac.Extensions.DependencyInjection.AzureFunctions/ScopedJobActivator.cs b/Autofac.Extensions.DependencyInjection.AzureFunctions/ScopedJobActivator.cs index a9bed94..4e27744 100644 --- a/Autofac.Extensions.DependencyInjection.AzureFunctions/ScopedJobActivator.cs +++ b/Autofac.Extensions.DependencyInjection.AzureFunctions/ScopedJobActivator.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; +using System.Diagnostics; namespace Autofac.Extensions.DependencyInjection.AzureFunctions { @@ -25,10 +26,9 @@ public T CreateInstance() public T CreateInstance(IFunctionInstanceEx functionInstance) { var scope = functionInstance.InstanceServices.GetService()?.Scope ?? _serviceProvider.GetRequiredService()?.Scope; - // Some dependencies of ILoggerFactory are registered after - // FunctionsStartup, thus not allowing us to get the - // ILoggerFactory from Autofac container. + // FunctionsStartup, on a separate ServicesCollection, thus + // not allowing us to get the ILoggerFactory from Autofac container. // So we are retrieving it from InstanceServices. var loggerFactory = functionInstance.InstanceServices.GetService() ?? scope.Resolve(); scope.Resolve( @@ -43,6 +43,26 @@ public T CreateInstance(IFunctionInstanceEx functionInstance) new NamedParameter(LoggerModule.functionNameParam, functionName) ); + // Add the functionInstanceEx itself to the scope + scope.Resolve( + new NamedParameter(ConfigurationExtensions.functionInstanceParam, functionInstance) + ); + if (ConfigurationExtensions.IEnvironmentType != null) // Required for TelemetryClient + { + var iEnvironment = functionInstance.InstanceServices.GetService(ConfigurationExtensions.IEnvironmentType); + scope.Resolve(ConfigurationExtensions.IEnvironmentType, new NamedParameter(ConfigurationExtensions.iEnvironmentParam, iEnvironment)); + } + if (Activity.Current == null) + { + var activity = new Activity(functionName); + Activity.Current = activity.Start(); + + scope.CurrentScopeEnding += (sender, e) => + { + activity.Stop(); + }; + } + return CreateInstance(scope); } diff --git a/Autofac.Extensions.DependencyInjection.AzureFunctions/Scopes.cs b/Autofac.Extensions.DependencyInjection.AzureFunctions/Scopes.cs index 624c3d3..ad11049 100644 --- a/Autofac.Extensions.DependencyInjection.AzureFunctions/Scopes.cs +++ b/Autofac.Extensions.DependencyInjection.AzureFunctions/Scopes.cs @@ -1,6 +1,6 @@ -using Autofac.Builder; -using System; +using System; using System.Linq; +using Autofac.Builder; namespace Autofac.Extensions.DependencyInjection.AzureFunctions { @@ -12,7 +12,7 @@ public static class Scopes /// /// Represents the scope of a function trigger request. /// - public const string RootLifetimeScopeTag = "AutofacFunctionsScope"; + public const string LifetimeScopeTag = "AutofacFunctionsScope"; /// /// Share one instance of the component within the context of a single @@ -32,7 +32,7 @@ public static IRegistrationBuilder InstancePerTr if (registration == null) throw new ArgumentNullException(nameof(registration)); - var tags = new[] { Scopes.RootLifetimeScopeTag }.Concat(lifetimeScopeTags).ToArray(); + var tags = new[] { Scopes.LifetimeScopeTag }.Concat(lifetimeScopeTags).ToArray(); return registration.InstancePerMatchingLifetimeScope(tags); } diff --git a/SampleAutofacFunction/Functions/Function3.cs b/SampleAutofacFunction/Functions/Function3.cs new file mode 100644 index 0000000..14ad31f --- /dev/null +++ b/SampleAutofacFunction/Functions/Function3.cs @@ -0,0 +1,41 @@ +using Microsoft.Azure.WebJobs; +using Microsoft.Extensions.Logging; +using SampleAutofacFunction.Services; +using System; +using System.Diagnostics; +using System.Threading.Tasks; + +namespace SampleAutofacFunction.Functions +{ + public class Function3 : IDisposable + { + private readonly IService1 _service1; + private readonly ILogger _logger; + private readonly Guid _id = Guid.NewGuid(); + + public Function3(IService1 service1, ILogger logger) + { + _service1 = service1; + _logger = logger; + _logger.LogWarning($"Creating {this}"); + } + + public void Dispose() + { + _logger.LogWarning($"Disposing {this}"); + } + + [FunctionName(nameof(Function3))] + public async Task Run([TimerTrigger("0 */5 * * * *", RunOnStartup = true)] TimerInfo timer) + { + await Task.Delay(2000); + Activity.Current.AddTag("Test", "Hello World"); + _logger.LogInformation($"C# Timer trigger function processed."); + } + + public override string ToString() + { + return $"{_id} ({nameof(Function1)})"; + } + } +} diff --git a/SampleAutofacFunction/SampleAutofacFunction.csproj b/SampleAutofacFunction/SampleAutofacFunction.csproj index 0487392..3824b54 100644 --- a/SampleAutofacFunction/SampleAutofacFunction.csproj +++ b/SampleAutofacFunction/SampleAutofacFunction.csproj @@ -1,13 +1,17 @@  - netcoreapp3.1 - v3 + net6.0 + v4 - - - - + + + + + + + +