diff --git a/DotNetWorker.sln b/DotNetWorker.sln
index 0fc5bb848..e8aca308b 100644
--- a/DotNetWorker.sln
+++ b/DotNetWorker.sln
@@ -140,6 +140,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Worker.Extensions.Shared.Te
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Worker.Extensions.Http.AspNetCore.Analyzers", "extensions\Worker.Extensions.Http.AspNetCore.Analyzers\Worker.Extensions.Http.AspNetCore.Analyzers.csproj", "{7B6C2920-7A02-43B2-8DA0-7B76B9FAFC6B}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Net7Worker", "samples\Net7Worker\Net7Worker.csproj", "{BE1F79C3-24FA-4BC8-BAB2-C1AD321B13FF}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependentAssemblyWithFunctions.NetStandard", "test\DependentAssemblyWithFunctions.NetStandard\DependentAssemblyWithFunctions.NetStandard.csproj", "{198DA072-F94F-4585-A744-97B3DAC21686}"
EndProject
Global
@@ -344,6 +346,10 @@ Global
{D8E79B53-9A44-46CC-9D7A-E9494FC8CAF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8E79B53-9A44-46CC-9D7A-E9494FC8CAF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8E79B53-9A44-46CC-9D7A-E9494FC8CAF4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BE1F79C3-24FA-4BC8-BAB2-C1AD321B13FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BE1F79C3-24FA-4BC8-BAB2-C1AD321B13FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BE1F79C3-24FA-4BC8-BAB2-C1AD321B13FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BE1F79C3-24FA-4BC8-BAB2-C1AD321B13FF}.Release|Any CPU.Build.0 = Release|Any CPU
{B6342174-5436-4846-B43C-39D8E34AE5CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6342174-5436-4846-B43C-39D8E34AE5CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6342174-5436-4846-B43C-39D8E34AE5CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -417,6 +423,7 @@ Global
{D8E79B53-9A44-46CC-9D7A-E9494FC8CAF4} = {AA4D318D-101B-49E7-A4EC-B34165AEDB33}
{B6342174-5436-4846-B43C-39D8E34AE5CF} = {FD7243E4-BF18-43F8-8744-BA1D17ACF378}
{7B6C2920-7A02-43B2-8DA0-7B76B9FAFC6B} = {A7B4FF1E-3DF7-4F28-9333-D0961CDDF702}
+ {BE1F79C3-24FA-4BC8-BAB2-C1AD321B13FF} = {9D6603BD-7EA2-4D11-A69C-0D9E01317FD6}
{198DA072-F94F-4585-A744-97B3DAC21686} = {B5821230-6E0A-4535-88A9-ED31B6F07596}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
diff --git a/build/Sdk.slnf b/build/Sdk.slnf
new file mode 100644
index 000000000..5921585a6
--- /dev/null
+++ b/build/Sdk.slnf
@@ -0,0 +1,10 @@
+{
+ "solution": {
+ "path": "..\\DotNetWorker.sln",
+ "projects": [
+ "sdk\\Sdk.Analyzers\\Sdk.Analyzers.csproj",
+ "sdk\\Sdk.Generators\\Sdk.Generators.csproj",
+ "sdk\\Sdk\\Sdk.csproj"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionApp/FunctionApp.csproj b/samples/FunctionApp/FunctionApp.csproj
index 5edab0f0b..36e8ff2d5 100644
--- a/samples/FunctionApp/FunctionApp.csproj
+++ b/samples/FunctionApp/FunctionApp.csproj
@@ -7,6 +7,7 @@
<_FunctionsSkipCleanOutput>true
true
..\..\key.snk
+ 1.17.2
DEBUG;TRACE
@@ -14,7 +15,7 @@
-
+
diff --git a/sdk/Sdk/ExtensionsCsprojGenerator.cs b/sdk/Sdk/ExtensionsCsprojGenerator.cs
index 384182d71..c08f92677 100644
--- a/sdk/Sdk/ExtensionsCsprojGenerator.cs
+++ b/sdk/Sdk/ExtensionsCsprojGenerator.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Azure.Functions.Worker.Sdk
{
internal class ExtensionsCsprojGenerator
{
- private const string ExtensionsProjectName = "WorkerExtensions.csproj";
+ internal const string ExtensionsProjectName = "WorkerExtensions.csproj";
private readonly IDictionary _extensions;
private readonly string _outputPath;
@@ -31,9 +31,20 @@ public void Generate()
{
var extensionsCsprojFilePath = Path.Combine(_outputPath, ExtensionsProjectName);
- RecreateDirectory(_outputPath);
+ string csproj = GetCsProjContent();
+ if (File.Exists(extensionsCsprojFilePath))
+ {
+ string existing = File.ReadAllText(extensionsCsprojFilePath);
+ if (string.Equals(csproj, existing, StringComparison.Ordinal))
+ {
+ // If contents are the same, only touch the file to update timestamp.
+ File.SetLastWriteTimeUtc(extensionsCsprojFilePath, DateTime.UtcNow);
+ return;
+ }
+ }
- WriteExtensionsCsProj(extensionsCsprojFilePath);
+ RecreateDirectory(_outputPath);
+ File.WriteAllText(extensionsCsprojFilePath, csproj);
}
private void RecreateDirectory(string directoryPath)
@@ -46,13 +57,6 @@ private void RecreateDirectory(string directoryPath)
Directory.CreateDirectory(directoryPath);
}
- private void WriteExtensionsCsProj(string filePath)
- {
- string csprojContent = GetCsProjContent();
-
- File.WriteAllText(filePath, csprojContent);
- }
-
internal string GetCsProjContent()
{
string extensionReferences = GetExtensionReferences();
diff --git a/sdk/Sdk/FunctionMetadataGenerator.cs b/sdk/Sdk/FunctionMetadataGenerator.cs
index 31e30ac09..6fe392c49 100644
--- a/sdk/Sdk/FunctionMetadataGenerator.cs
+++ b/sdk/Sdk/FunctionMetadataGenerator.cs
@@ -7,6 +7,7 @@
using System.Dynamic;
using System.IO;
using System.Linq;
+using Microsoft.Build.Framework;
using Mono.Cecil;
using Mono.Collections.Generic;
@@ -42,44 +43,33 @@ public IDictionary Extensions
}
}
- public IEnumerable GenerateFunctionMetadata(string assemblyPath, IEnumerable referencePaths)
+ public IEnumerable GenerateFunctionMetadata(string assemblyPath, IEnumerable referencePaths)
{
- string sourcePath = Path.GetDirectoryName(assemblyPath);
+ var targetAssemblies = new List() { assemblyPath };
- var targetAssemblies = new List(Directory.GetFiles(sourcePath, "*.dll"));
+ // We don't need to scan assemblies that come from a framework (.NET, AspNetCore), they won't have functions types in them.
+ targetAssemblies.AddRange(referencePaths.Where(x => x.GetMetadata("FrameworkReferenceName") == "").Select(x => x.ItemSpec));
+ _logger.LogMessage($"Found {targetAssemblies.Count} assemblies to evaluate.");
- if (!assemblyPath.EndsWith(".dll"))
+ var resolver = new DefaultAssemblyResolver();
+ foreach (string referencePath in referencePaths.Select(p => Path.GetDirectoryName(p.ItemSpec)).Distinct())
{
- targetAssemblies.Add(assemblyPath);
+ resolver.AddSearchDirectory(referencePath);
}
+ ReaderParameters readerParams = new ReaderParameters { AssemblyResolver = resolver };
var functions = new List();
-
- _logger.LogMessage($"Found {targetAssemblies.Count} assemblies to evaluate in '{sourcePath}':");
-
foreach (var path in targetAssemblies)
{
using (_logger.Indent())
{
- _logger.LogMessage($"{Path.GetFileName(path)}");
+ _logger.LogMessage($"Collecting function metadata from {Path.GetFileName(path)}.");
using (_logger.Indent())
{
try
{
- BaseAssemblyResolver resolver = new DefaultAssemblyResolver();
-
- foreach (string referencePath in referencePaths.Select(p => Path.GetDirectoryName(p)).Distinct())
- {
- resolver.AddSearchDirectory(referencePath);
- }
-
- resolver.AddSearchDirectory(Path.GetDirectoryName(path));
-
- ReaderParameters readerParams = new ReaderParameters { AssemblyResolver = resolver };
-
var moduleDefinition = ModuleDefinition.ReadModule(path, readerParams);
-
functions.AddRange(GenerateFunctionMetadata(moduleDefinition));
}
catch (BadImageFormatException)
diff --git a/sdk/Sdk/Sdk.csproj b/sdk/Sdk/Sdk.csproj
index 6dd2ae84e..8d70b189b 100644
--- a/sdk/Sdk/Sdk.csproj
+++ b/sdk/Sdk/Sdk.csproj
@@ -2,7 +2,8 @@
17
- 2
+ 3
+ -preview1
netstandard2.0;net472
Microsoft.Azure.Functions.Worker.Sdk
This package provides development time support for the Azure Functions .NET Worker.
diff --git a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets
index 7ad914b23..6e807f0b8 100644
--- a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets
+++ b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets
@@ -8,437 +8,215 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
***********************************************************************************************
-->
-
-
- <_ToolingSuffix>
- <_AzureFunctionsNotSet Condition="'$(AzureFunctionsVersion)' == ''">true
- v3
- <_ToolingSuffix Condition="($(AzureFunctionsVersion.StartsWith('v3',StringComparison.OrdinalIgnoreCase)) Or $(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase))) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v5.0'">net5-isolated
- <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v6.0'">net6-isolated
- <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v7.0'">net7-isolated
- <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v8.0'">net8-isolated
- <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETFramework'">netfx-isolated
- $(_ToolingSuffix)
- <_FunctionsTaskFramework Condition=" '$(MSBuildRuntimeType)' == 'Core'">netstandard2.0
- <_FunctionsTaskFramework Condition=" '$(_FunctionsTaskFramework)' == ''">net472
- <_FunctionsTasksDir Condition=" '$(_FunctionsTasksDir)'=='' ">$(MSBuildThisFileDirectory)..\tools\$(_FunctionsTaskFramework)\
- <_FunctionsTaskAssemblyFullPath Condition=" '$(_FunctionsTaskAssemblyFullPath)'=='' ">$(_FunctionsTasksDir)\Microsoft.Azure.Functions.Worker.Sdk.dll
-
- <_FunctionsWorkerConfigInputFile>$(MSBuildThisFileDirectory)\..\tools\worker.config.json
-
- <_FunctionsMetadataLoaderExtensionFile>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll
- <_FunctionsExtensionsDirectory>.azurefunctions
- <_FunctionsExtensionsJsonName>extensions.json
- <_FunctionsExtensionsFullPublish Condition="$(NoBuild) == '' And $(_FunctionsExtensionsFullPublish) == ''">True
- <_FunctionsExtensionsFullPublish Condition="$(_FunctionsExtensionsFullPublish) == ''">!$(NoBuild)
- $(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed.Functions\
-
- false
- true
- $(FunctionsEnableWorkerIndexing)
- $(FunctionsEnableWorkerIndexing)
- true
- true
- true
- $(RootNamespace.Replace("-", "_"))
-
-
-
-
-
+
+
+ <_ToolingSuffix>
+ <_AzureFunctionsNotSet Condition="'$(AzureFunctionsVersion)' == ''">true
+ v4
+ <_ToolingSuffix Condition="($(AzureFunctionsVersion.StartsWith('v3',StringComparison.OrdinalIgnoreCase)) Or $(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase))) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v5.0'">net5-isolated
+ <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v6.0'">net6-isolated
+ <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v7.0'">net7-isolated
+ <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v8.0'">net8-isolated
+ <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETFramework'">netfx-isolated
+ $(_ToolingSuffix)
+ <_FunctionsTaskFramework Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0
+ <_FunctionsTaskFramework Condition="'$(_FunctionsTaskFramework)' == ''">net472
+ <_FunctionsTasksDir Condition="'$(_FunctionsTasksDir)'==''">$(MSBuildThisFileDirectory)..\tools\$(_FunctionsTaskFramework)\
+ <_FunctionsTaskAssemblyFullPath Condition=" '$(_FunctionsTaskAssemblyFullPath)'=='' ">$(_FunctionsTasksDir)\Microsoft.Azure.Functions.Worker.Sdk.dll
+
+ <_FunctionsExtensionCommonProps>ImportDirectoryBuildProps=false;ImportDirectoryBuildTargets=false;ImportDirectoryPackagesProps=false
+ <_FunctionsExtensionRemoveProps>TargetFramework;Platform;RuntimeIdentifier;SelfContained;PublishSingleFile;PublishReadyToRun;UseCurrentRuntimeIdentifier;WebPublishMethod;PublishProfile;DeployOnBuild;PublishDir
+ <_FunctionsWorkerConfigInputFile>$(MSBuildThisFileDirectory)\..\tools\worker.config.json
+
+ <_FunctionsMetadataLoaderExtensionFile>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll
+ <_FunctionsExtensionsDirectory>.azurefunctions
+ <_FunctionsExtensionsJsonName>extensions.json
+ $(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed.Functions\
+
+ false
+ true
+ $(FunctionsEnableWorkerIndexing)
+ $(FunctionsEnableWorkerIndexing)
+
+ true
+ true
+
+ <_FunctionsGenerateExtensionProject Condition="'$(DesignTimeBuild)' != 'true'">true
+ $(RootNamespace.Replace("-", "_"))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
+
+
-
-
-
-
-
-
-
-
+
+
-
- <_FunctionsWorkerExecutableFileName >$(TargetName)$(TargetExt)
-
-
-
- <_FunctionsNativeExecutableExtension Condition="($(RuntimeIdentifier.StartsWith('win')) or $(DefaultAppHostRuntimeIdentifier.StartsWith('win')))">.exe
- <_FunctionsWorkerExecutableFileName Condition="'$(PublishAot)' != 'true'">$(TargetName).dll
- <_FunctionsWorkerExecutableFileName Condition="'$(PublishAot)' == 'true'">$(TargetName)$(_FunctionsNativeExecutableExtension)
+
+
+
+ <_FunctionsMetadataPath>$(IntermediateOutputPath)functions.metadata
+ <_FunctionsWorkerConfigPath>$(IntermediateOutputPath)worker.config.json
+ $(IntermediateOutputPath)WorkerExtensions
+ $([System.IO.Path]::GetFullPath($(ExtensionsCsProjDirectory)))
+ $([System.IO.Path]::Combine($(ExtensionsCsProjDirectory), WorkerExtensions.csproj))
+ <_FunctionsIntermediateExtensionJsonPath>$(ExtensionsCsProjDirectory)\buildout\bin\$(_FunctionsExtensionsJsonName)
+ <_FunctionsIntermediateExtensionUpdatedJsonPath>$(IntermediateOutputPath)$(_FunctionsExtensionsJsonName)
-
-
-
-
-
- $(TargetDir)\worker.config.json
- $([System.IO.Path]::Combine($([System.IO.Path]::GetTempPath()), $([System.IO.Path]::GetRandomFileName())))
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(TargetDir)\worker.config.json
- $([System.IO.Path]::Combine($([System.IO.Path]::GetTempPath()), $([System.IO.Path]::GetRandomFileName())))
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <_FilesInTargetDir Include="$(TargetDir)**\*" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(FunctionsDir)
- $(PublishDir)\
- $(PublishDir)bin\$(TargetFileName)
- $(FunctionsDir)
-
-
-
-
-
-
-
-
-
-
-
- $(PublishIntermediateOutputPath)
- $(PublishDir)\
- $(PublishDir)bin\$(TargetFileName)
- $(PublishIntermediateOutputPath)
-
-
-
-
- <_PublishTempFiles Include="$(PublishIntermediateOutputPath)**\*.*" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
- ============================================================
- -->
+
+
+
+
+
+
-
- _InitializeDeployOnBuildProperties;
- Publish;
- $(_DotNetPublishFiles);
-
+ <_FunctionsExecutable>dotnet
+
+
+ <_FunctionsExecutable Condition="'$(SelfContained)' == 'true' AND '%(Identity)' == '$(AppHostIntermediatePath)'">{WorkerRoot}%(None.Link)
+ <_FunctionsExecutable Condition="$(TargetFrameworkIdentifier) == '.NETFramework'">{WorkerRoot}$(TargetName)$(TargetExt)
-
-
-
-
-
- $(PublishDir)\worker.config.json
- $([System.IO.Path]::Combine($([System.IO.Path]::GetTempPath()), $([System.IO.Path]::GetRandomFileName())))
-
-
-
-
-
-
-
-
-
-
-
-
- $(PublishDir)\worker.config.json
- $([System.IO.Path]::Combine($([System.IO.Path]::GetTempPath()), $([System.IO.Path]::GetRandomFileName())))
-
-
-
-
-
-
-
+
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
- _GenerateFunctionsAndCopyContentFiles;
- _WorkerExtensionsRestorePublish;
- _WorkerExtensionsFullPublish;
- _WorkerExtensionsPublishCopy;
- _EnhanceFunctionsExtensionsMetadataPostPublish
-
-
- _GenerateFunctionsAndCopyContentFiles;
- _WorkerExtensionsPublishCopyNoBuild
-
-
+
+
+
+
+
+
+
+
+ <_ExtensionBinaries Include="$(ExtensionsCsProjDirectory)\buildout\bin\**"
+ Exclude="$(ExtensionsCsProjDirectory)\buildout\bin\runtimes\**;$(_FunctionsIntermediateExtensionJsonPath)"
+ CopyToOutputDirectory="PreserveNewest"
+ CopyToPublishDirectory="PreserveNewest" />
+ <_ExtensionRuntimeBinaries Include="$(ExtensionsCsProjDirectory)\buildout\runtimes\**"
+ CopyToOutputDirectory="PreserveNewest"
+ CopyToPublishDirectory="PreserveNewest" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_NoneWithTargetPath Include="@(_ExtensionFilesWithTargetPath)" TargetPath="$(_FunctionsExtensionsDirectory)/%(_ExtensionFilesWithTargetPath.TargetPath)" />
+
+
+
+
+
+ <_WorkerExtFilesToClean Include="$(ExtensionsCsProjDirectory)\**" Condition="'$(ExtensionsCsProjDirectory)' != ''" />
+ <_WorkerExtFilesToClean Include="$(TargetDir)$(_FunctionsExtensionsDirectory)\**" />
+ <_WorkerExtFilesToClean Include="$(_FunctionsMetadataPath)" />
+ <_WorkerExtFilesToClean Include="$(_FunctionsWorkerConfigPath)" />
+ <_WorkerExtFilesToClean Include="$(TargetDir)worker.config.json" />
+ <_WorkerExtFilesToClean Include="$(TargetDir)extensions.json" />
+ <_WorkerExtFilesToClean Include="$(TargetDir)functions.metadata" />
+ <_WorkerExtFilesToClean Include="$(_FunctionsIntermediateExtensionUpdatedJsonPath)" />
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs b/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs
index 8fbaf5c13..c76bb4871 100644
--- a/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs
+++ b/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs
@@ -34,8 +34,6 @@ public override bool Execute()
string newJson = JsonSerializer.Serialize(extensionsMetadata, _serializerOptions);
File.WriteAllText(OutputPath, newJson);
- File.Delete(ExtensionsJsonPath);
-
return true;
}
}
diff --git a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs
index 8b66d6b49..e8e42cee2 100644
--- a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs
+++ b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs
@@ -45,7 +45,7 @@ public override bool Execute()
{
var functionGenerator = new FunctionMetadataGenerator(MSBuildLogger);
- var functions = functionGenerator.GenerateFunctionMetadata(AssemblyPath!, ReferencePaths.Select(p => p.ItemSpec));
+ var functions = functionGenerator.GenerateFunctionMetadata(AssemblyPath!, ReferencePaths ?? Enumerable.Empty());
var extensions = functionGenerator.Extensions;
var extensionsCsProjGenerator = new ExtensionsCsprojGenerator(extensions, ExtensionsCsProjFilePath!, AzureFunctionsVersion!, TargetFrameworkIdentifier!, TargetFrameworkVersion!);
diff --git a/sdk/release_notes.md b/sdk/release_notes.md
index 5332de1d4..d9c704edd 100644
--- a/sdk/release_notes.md
+++ b/sdk/release_notes.md
@@ -4,7 +4,7 @@
- My change description (#PR/#issue)
-->
-### Microsoft.Azure.Functions.Worker.Sdk 1.17.2 (meta package)
-
-- Revert changes from #1946
+### Microsoft.Azure.Functions.Worker.Sdk 1.17.13-preview1 (meta package)
+- Re-add SDK refactors that were reverted in #2313 (#2347)
+- Address assembly scanning regression (#2347)
diff --git a/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj b/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj
index 887a44c4a..2469eba63 100644
--- a/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj
+++ b/test/E2ETests/E2EApps/E2EApp/E2EApp.csproj
@@ -44,7 +44,7 @@
-
+
\ No newline at end of file
diff --git a/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs b/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs
index c0b32d779..ce06d4e86 100644
--- a/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs
+++ b/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs
@@ -1,7 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
+using System;
using System.Collections.Generic;
+using System.IO;
using Microsoft.Azure.Functions.Worker.Sdk;
using Xunit;
@@ -9,8 +11,48 @@ namespace Microsoft.Azure.Functions.SdkTests
{
public class ExtensionsCsProjGeneratorTests
{
- [Fact]
- public void GetCsProjContent_Succeeds_functions_v3()
+ public enum FuncVersion
+ {
+ V3,
+ V4,
+ }
+
+ [Theory]
+ [InlineData(FuncVersion.V3)]
+ [InlineData(FuncVersion.V4)]
+ public void GetCsProjContent_Succeeds(FuncVersion version)
+ {
+ var generator = GetGenerator(version);
+ string actual = generator.GetCsProjContent().Replace("\r\n", "\n");
+ string expected = ExpectedCsproj(version).Replace("\r\n", "\n");
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory]
+ [InlineData(FuncVersion.V3)]
+ [InlineData(FuncVersion.V4)]
+ public void GetCsProjContent_IncrementalSupport(FuncVersion version)
+ {
+ DateTime RunGenerate(string subPath, out string contents)
+ {
+ var generator = GetGenerator(version, subPath);
+ generator.Generate();
+
+ string path = Path.Combine(subPath, ExtensionsCsprojGenerator.ExtensionsProjectName);
+ contents = File.ReadAllText(path);
+ var csproj = new FileInfo(Path.Combine(subPath, ExtensionsCsprojGenerator.ExtensionsProjectName));
+ return csproj.LastWriteTimeUtc;
+ }
+
+ string subPath = Guid.NewGuid().ToString();
+ DateTime firstRun = RunGenerate(subPath, out string first);
+ DateTime secondRun = RunGenerate(subPath, out string second);
+
+ Assert.NotEqual(firstRun, secondRun);
+ Assert.Equal(first, second);
+ }
+
+ static ExtensionsCsprojGenerator GetGenerator(FuncVersion version, string subPath = "")
{
IDictionary extensions = new Dictionary
{
@@ -19,13 +61,22 @@ public void GetCsProjContent_Succeeds_functions_v3()
{ "Microsoft.Azure.WebJobs.Extensions", "2.0.0" },
};
- var generator = new ExtensionsCsprojGenerator(extensions, "", "v3", Constants.NetCoreApp, Constants.NetCoreVersion31);
-
- string actualCsproj = generator.GetCsProjContent().Replace("\r\n", "\n");
-
- Assert.Equal(ExpectedCsProjV3(), actualCsproj);
+ return version switch
+ {
+ FuncVersion.V3 => new ExtensionsCsprojGenerator(extensions, subPath, "v3", Constants.NetCoreApp, Constants.NetCoreVersion31),
+ FuncVersion.V4 => new ExtensionsCsprojGenerator(extensions, subPath, "v4", Constants.NetCoreApp, Constants.NetCoreVersion6),
+ _ => throw new ArgumentOutOfRangeException(nameof(version)),
+ };
}
+ private static string ExpectedCsproj(FuncVersion version)
+ => version switch
+ {
+ FuncVersion.V3 => ExpectedCsProjV3(),
+ FuncVersion.V4 => ExpectedCsProjV4(),
+ _ => throw new ArgumentOutOfRangeException(nameof(version)),
+ };
+
private static string ExpectedCsProjV3()
{
return @"
@@ -51,27 +102,10 @@ private static string ExpectedCsProjV3()
";
- }
-
- [Fact]
- public void GetCsProjContent_Succeeds_functions_v4()
- {
- IDictionary extensions = new Dictionary
- {
- { "Microsoft.Azure.WebJobs.Extensions.Storage", "4.0.3" },
- { "Microsoft.Azure.WebJobs.Extensions.Http", "3.0.0" },
- { "Microsoft.Azure.WebJobs.Extensions", "2.0.0" },
- };
-
- var generator = new ExtensionsCsprojGenerator(extensions, "", "v4", Constants.NetCoreApp, Constants.NetCoreVersion6);
-
- string actualCsproj = generator.GetCsProjContent().Replace("\r\n", "\n");
-
- Assert.Equal(ExpectedCsProjV4(), actualCsproj);
- }
-
- private static string ExpectedCsProjV4()
- {
+ }
+
+ private static string ExpectedCsProjV4()
+ {
return @"
@@ -94,7 +128,7 @@ private static string ExpectedCsProjV4()
-";
- }
+";
+ }
}
}
diff --git a/test/Resources/Projects/FunctionApp01/FunctionApp01.csproj b/test/Resources/Projects/FunctionApp01/FunctionApp01.csproj
new file mode 100644
index 000000000..88de5f212
--- /dev/null
+++ b/test/Resources/Projects/FunctionApp01/FunctionApp01.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ 1.17.2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Resources/Projects/FunctionApp01/HttpFunction.cs b/test/Resources/Projects/FunctionApp01/HttpFunction.cs
new file mode 100644
index 000000000..747abb8bc
--- /dev/null
+++ b/test/Resources/Projects/FunctionApp01/HttpFunction.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.Net;
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Http;
+using Microsoft.Extensions.Logging;
+
+namespace FunctionApp01
+{
+ public class HttpFunction
+ {
+ [Function("FunctionApp01_Hello")]
+ public HttpResponseData Hello([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req)
+ {
+ return req.CreateResponse(HttpStatusCode.OK);
+ }
+ }
+}
diff --git a/test/Resources/Projects/FunctionApp01/Program.cs b/test/Resources/Projects/FunctionApp01/Program.cs
new file mode 100644
index 000000000..3751555cb
--- /dev/null
+++ b/test/Resources/Projects/FunctionApp01/Program.cs
@@ -0,0 +1,2 @@
+// See https://aka.ms/new-console-template for more information
+Console.WriteLine("Hello, World!");
diff --git a/test/Resources/Projects/FunctionLib01/FunctionLib01.csproj b/test/Resources/Projects/FunctionLib01/FunctionLib01.csproj
new file mode 100644
index 000000000..8a8610cef
--- /dev/null
+++ b/test/Resources/Projects/FunctionLib01/FunctionLib01.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/test/Resources/Projects/FunctionLib01/HttpFunction.cs b/test/Resources/Projects/FunctionLib01/HttpFunction.cs
new file mode 100644
index 000000000..456d7f5cf
--- /dev/null
+++ b/test/Resources/Projects/FunctionLib01/HttpFunction.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.Net;
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Http;
+using Microsoft.Extensions.Logging;
+
+namespace FunctionLib01
+{
+ public class HttpFunction
+ {
+ [Function("FunctionLib01_Hello")]
+ public HttpResponseData Hello([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req)
+ {
+ return req.CreateResponse(HttpStatusCode.OK);
+ }
+ }
+}
diff --git a/test/SdkE2ETests/InnerBuildTests.cs b/test/SdkE2ETests/InnerBuildTests.cs
new file mode 100644
index 000000000..e0f73a152
--- /dev/null
+++ b/test/SdkE2ETests/InnerBuildTests.cs
@@ -0,0 +1,119 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.IO;
+using System.Threading.Tasks;
+using Newtonsoft.Json.Linq;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.Azure.Functions.SdkE2ETests
+{
+ public class InnerBuildTests
+ {
+ private readonly ITestOutputHelper _testOutputHelper;
+
+ public InnerBuildTests(ITestOutputHelper testOutputHelper)
+ {
+ _testOutputHelper = testOutputHelper;
+ }
+
+ [Fact]
+ public async Task Build_ScansReferences()
+ {
+ string outputDir = await TestUtility.InitializeTestAsync(_testOutputHelper, nameof(Build_ScansReferences));
+ string projectFileDirectory = Path.Combine(TestUtility.TestResourcesProjectsRoot, "FunctionApp01", "FunctionApp01.csproj");
+
+ await TestUtility.RestoreAndBuildProjectAsync(projectFileDirectory, outputDir, null, _testOutputHelper);
+
+ // Verify extensions.json contents
+ string extensionsJsonPath = Path.Combine(outputDir, "extensions.json");
+ Assert.True(File.Exists(extensionsJsonPath));
+
+ JToken extensionsJsonContents = JObject.Parse(File.ReadAllText(extensionsJsonPath));
+ JToken expectedExtensionsJson = JObject.Parse(@"{
+ ""extensions"": [
+ {
+ ""name"": ""SqlDurabilityProvider"",
+ ""typeName"": ""DurableTask.SqlServer.AzureFunctions.SqlDurabilityProviderStartup, DurableTask.SqlServer.AzureFunctions, Version=1.2.0.0, Culture=neutral, PublicKeyToken=2ea3c3a96309d850"",
+ ""hintPath"": ""./.azurefunctions/DurableTask.SqlServer.AzureFunctions.dll""
+ },
+ {
+ ""name"": ""DurableTask"",
+ ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.DurableTask.DurableTaskWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.DurableTask, Version=2.0.0.0, Culture=neutral, PublicKeyToken=014045d636e89289"",
+ ""hintPath"": ""./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.DurableTask.dll""
+ },
+ {
+ ""name"": ""Startup"",
+ ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.Startup, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c"",
+ ""hintPath"": ""./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll""
+ }
+ ]
+}");
+
+ Assert.True(JToken.DeepEquals(expectedExtensionsJson, extensionsJsonContents));
+
+ // Verify functions.metadata contents
+ string functionsMetadataPath = Path.Combine(outputDir, "functions.metadata");
+ Assert.True(File.Exists(functionsMetadataPath));
+
+ JToken functionsMetadataContents = JArray.Parse(File.ReadAllText(functionsMetadataPath));
+ JToken expectedFunctionsMetadata = JArray.Parse(@"[
+ {
+ ""name"": ""FunctionApp01_Hello"",
+ ""scriptFile"": ""FunctionApp01.dll"",
+ ""entryPoint"": ""FunctionApp01.HttpFunction.Hello"",
+ ""language"": ""dotnet-isolated"",
+ ""properties"": {
+ ""IsCodeless"": false
+ },
+ ""bindings"": [
+ {
+ ""name"": ""req"",
+ ""direction"": ""In"",
+ ""type"": ""httpTrigger"",
+ ""authLevel"": ""Anonymous"",
+ ""methods"": [
+ ""get""
+ ],
+ ""properties"": {}
+ },
+ {
+ ""name"": ""$return"",
+ ""type"": ""http"",
+ ""direction"": ""Out""
+ }
+ ]
+ },
+ {
+ ""name"": ""FunctionLib01_Hello"",
+ ""scriptFile"": ""FunctionLib01.dll"",
+ ""entryPoint"": ""FunctionLib01.HttpFunction.Hello"",
+ ""language"": ""dotnet-isolated"",
+ ""properties"": {
+ ""IsCodeless"": false
+ },
+ ""bindings"": [
+ {
+ ""name"": ""req"",
+ ""direction"": ""In"",
+ ""type"": ""httpTrigger"",
+ ""authLevel"": ""Anonymous"",
+ ""methods"": [
+ ""get""
+ ],
+ ""properties"": {}
+ },
+ {
+ ""name"": ""$return"",
+ ""type"": ""http"",
+ ""direction"": ""Out""
+ }
+ ]
+ }
+]");
+
+ Assert.True(JToken.DeepEquals(expectedFunctionsMetadata, functionsMetadataContents));
+ }
+ }
+}
diff --git a/test/SdkE2ETests/TestUtility.cs b/test/SdkE2ETests/TestUtility.cs
index e78028079..b636691fd 100644
--- a/test/SdkE2ETests/TestUtility.cs
+++ b/test/SdkE2ETests/TestUtility.cs
@@ -27,7 +27,6 @@ public static class TestUtility
// Paths and executables
public static readonly string DotNetExecutable = "dotnet";
-
public static readonly string PathToRepoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\..\"));
public static readonly string SrcRoot = Path.Combine(PathToRepoRoot, "src");
public static readonly string SdkSolutionRoot = Path.Combine(PathToRepoRoot, "sdk");
@@ -36,9 +35,12 @@ public static class TestUtility
public static readonly string SamplesRoot = Path.Combine(PathToRepoRoot, "samples");
public static readonly string LocalPackages = Path.Combine(PathToRepoRoot, "local");
public static readonly string TestOutputDir = Path.Combine(Path.GetTempPath(), "FunctionsWorkerSdkE2ETests");
- public static readonly string DevPackPath = Path.Combine(PathToRepoRoot, "tools", "devpack.ps1");
+ public static readonly string TestResourcesProjectsRoot = Path.Combine(TestRoot, "Resources", "Projects");
+ public static readonly string NuGetOrgPackages = "https://api.nuget.org/v3/index.json";
public static readonly string NuGetPackageSource = LocalPackages;
+ public static readonly string SdkVersion = "99.99.99-test";
+ public static readonly string SdkBuildProj = Path.Combine(PathToRepoRoot, "build", "Sdk.slnf");
private static bool _isInitialized = false;
@@ -46,14 +48,10 @@ public static async Task InitializeTestAsync(ITestOutputHelper testOutpu
{
if (!_isInitialized)
{
- testOutputHelper.WriteLine($"Running {DevPackPath}");
-
- int? exitCode = await new ProcessWrapper().RunProcess("powershell", DevPackPath, SrcRoot, testOutputHelper);
- Assert.True(exitCode.HasValue && exitCode.Value == 0);
+ testOutputHelper.WriteLine($"Packing {SdkBuildProj} with version {SdkVersion}");
+ string arguments = $"pack {SdkBuildProj} -c {Configuration} -o {LocalPackages} -p:Version={SdkVersion}";
- // Build .NET Worker
- string dotnetArgs = $"build --configuration {Configuration}";
- exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, Path.Combine(SrcRoot, "DotNetWorker"), testOutputHelper: testOutputHelper);
+ int? exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, arguments, SrcRoot, testOutputHelper);
Assert.True(exitCode.HasValue && exitCode.Value == 0);
_isInitialized = true;
@@ -82,27 +80,44 @@ public static void ValidateFunctionsMetadata(string actualFilePath, string embed
}
}
- public static async Task RestoreAndPublishProjectAsync(string fullPathToProjFile, string outputDir, string additionalParams, ITestOutputHelper outputHelper)
+ public static async Task RestoreAndBuildProjectAsync(string fullPathToProjFile, string outputDir, string additionalParams, ITestOutputHelper outputHelper)
{
- await PackWorkerSdk(outputHelper);
+ // Name of the csproj
+ string projectNameToTest = Path.GetFileName(fullPathToProjFile);
+ string projectFileDirectory = Path.GetDirectoryName(fullPathToProjFile);
- await UpdateNugetPackagesForApp(fullPathToProjFile, outputHelper);
+ // Restore
+ outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Restoring...");
+ string dotnetArgs = $"restore {projectNameToTest} -s {NuGetOrgPackages} -s {LocalPackages} -p:SdkVersion={SdkVersion}";
+ int? exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, projectFileDirectory, testOutputHelper: outputHelper);
+ Assert.True(exitCode.HasValue && exitCode.Value == 0);
+ outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Done.");
+
+ // Build
+ outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Building...");
+ dotnetArgs = $"build {projectNameToTest} --configuration {Configuration} -o {outputDir} -p:SdkVersion={SdkVersion} {additionalParams}";
+ exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, projectFileDirectory, testOutputHelper: outputHelper);
+ Assert.True(exitCode.HasValue && exitCode.Value == 0);
+ outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Done.");
+ }
+ public static async Task RestoreAndPublishProjectAsync(string fullPathToProjFile, string outputDir, string additionalParams, ITestOutputHelper outputHelper)
+ {
// Name of the csproj
string projectNameToTest = Path.GetFileName(fullPathToProjFile);
string projectFileDirectory = Path.GetDirectoryName(fullPathToProjFile);
// Restore
outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Restoring...");
- string dotnetArgs = $"restore {projectNameToTest} --source {TestUtility.LocalPackages}";
- int? exitCode = await new ProcessWrapper().RunProcess(TestUtility.DotNetExecutable, dotnetArgs, projectFileDirectory, testOutputHelper: outputHelper);
+ string dotnetArgs = $"restore {projectNameToTest} -s {NuGetOrgPackages} -s {LocalPackages} -p:SdkVersion={SdkVersion}";
+ int? exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, projectFileDirectory, testOutputHelper: outputHelper);
Assert.True(exitCode.HasValue && exitCode.Value == 0);
outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Done.");
// Publish
outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Publishing...");
- dotnetArgs = $"publish {projectNameToTest} --configuration {TestUtility.Configuration} -o {outputDir} {additionalParams}";
- exitCode = await new ProcessWrapper().RunProcess(TestUtility.DotNetExecutable, dotnetArgs, projectFileDirectory, testOutputHelper: outputHelper);
+ dotnetArgs = $"publish {projectNameToTest} --configuration {Configuration} -o {outputDir} -p:SdkVersion={SdkVersion} {additionalParams}";
+ exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, projectFileDirectory, testOutputHelper: outputHelper);
Assert.True(exitCode.HasValue && exitCode.Value == 0);
outputHelper.WriteLine($"[{DateTime.UtcNow:O}] Done.");
}
@@ -120,25 +135,5 @@ private static string InitializeOutputDir(string testName)
return outputDir;
}
-
- private static async Task PackWorkerSdk(ITestOutputHelper testOutputHelper)
- {
- // Build solution
- int? exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, $"build --configuration {Configuration}", SdkProjectRoot, testOutputHelper: testOutputHelper);
- Assert.True(exitCode.HasValue && exitCode.Value == 0);
-
- // Pack Sdk project
- exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, $"pack --configuration {Configuration} -o {LocalPackages} --no-build", SdkProjectRoot, testOutputHelper: testOutputHelper);
- Assert.True(exitCode.HasValue && exitCode.Value == 0);
- }
-
- private static async Task UpdateNugetPackagesForApp(string projectFile, ITestOutputHelper testOutputHelper)
- {
- int? exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, $"remove {projectFile} package {WorkerSdkPackageName}", PathToRepoRoot, testOutputHelper: testOutputHelper);
- // If a previous run failed, this may have a -1 exit code. We'll continue anyway.
-
- exitCode = await new ProcessWrapper().RunProcess(DotNetExecutable, $"add {projectFile} package {WorkerSdkPackageName} -s {LocalPackages} --prerelease", SdkProjectRoot, testOutputHelper: testOutputHelper);
- Assert.True(exitCode.HasValue && exitCode.Value == 0);
- }
}
}