diff --git a/samples/FunctionApp/FunctionApp.csproj b/samples/FunctionApp/FunctionApp.csproj index e0c363aa..0683410b 100644 --- a/samples/FunctionApp/FunctionApp.csproj +++ b/samples/FunctionApp/FunctionApp.csproj @@ -9,7 +9,7 @@ - + diff --git a/sdk/Sdk/ExtensionsCsprojGenerator.cs b/sdk/Sdk/ExtensionsCsprojGenerator.cs index b8ba9558..81e7d0c5 100644 --- a/sdk/Sdk/ExtensionsCsprojGenerator.cs +++ b/sdk/Sdk/ExtensionsCsprojGenerator.cs @@ -10,8 +10,6 @@ namespace Microsoft.Azure.Functions.Worker.Sdk { internal class ExtensionsCsprojGenerator { - internal const string ExtensionsProjectName = "WorkerExtensions.csproj"; - private readonly IDictionary _extensions; private readonly string _outputPath; private readonly string _targetFrameworkIdentifier; @@ -29,22 +27,20 @@ public ExtensionsCsprojGenerator(IDictionary extensions, string public void Generate() { - var extensionsCsprojFilePath = Path.Combine(_outputPath, ExtensionsProjectName); - string csproj = GetCsProjContent(); - if (File.Exists(extensionsCsprojFilePath)) + if (File.Exists(_outputPath)) { - string existing = File.ReadAllText(extensionsCsprojFilePath); + string existing = File.ReadAllText(_outputPath); if (string.Equals(csproj, existing, StringComparison.Ordinal)) { // If contents are the same, only touch the file to update timestamp. - File.SetLastWriteTimeUtc(extensionsCsprojFilePath, DateTime.UtcNow); + File.SetLastWriteTimeUtc(_outputPath, DateTime.UtcNow); return; } } - RecreateDirectory(_outputPath); - File.WriteAllText(extensionsCsprojFilePath, csproj); + RecreateDirectory(Path.GetDirectoryName(_outputPath)); + File.WriteAllText(_outputPath, csproj); } private void RecreateDirectory(string directoryPath) diff --git a/sdk/Sdk/ExtensionsMetadata.cs b/sdk/Sdk/ExtensionsMetadata.cs index f7ed7912..2fcd1ae1 100644 --- a/sdk/Sdk/ExtensionsMetadata.cs +++ b/sdk/Sdk/ExtensionsMetadata.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System.Collections.Generic; @@ -9,6 +9,6 @@ namespace Microsoft.Azure.Functions.Worker.Sdk public class ExtensionsMetadata { [JsonPropertyName("extensions")] - public IEnumerable? Extensions { get; set; } + public List Extensions { get; set; } = new List(); } } diff --git a/sdk/Sdk/ExtensionsMetadataEnhancer.cs b/sdk/Sdk/ExtensionsMetadataEnhancer.cs index 9259dbc7..11266b74 100644 --- a/sdk/Sdk/ExtensionsMetadataEnhancer.cs +++ b/sdk/Sdk/ExtensionsMetadataEnhancer.cs @@ -2,7 +2,11 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; using System.Text.RegularExpressions; +using Mono.Cecil; namespace Microsoft.Azure.Functions.Worker.Sdk { @@ -25,6 +29,34 @@ public static void AddHintPath(IEnumerable extensions) } } + public static IEnumerable GetWebJobsExtensions(string fileName) + { + // NOTE: this is an incomplete approach to getting extensions and is intended only for our usages. + // Running this with arbitrary assemblies (especially user supplied) can lead to exceptions. + AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(fileName); + IEnumerable attributes = assembly.Modules.SelectMany(p => p.GetCustomAttributes()) + .Where(a => a.AttributeType.FullName == "Microsoft.Azure.WebJobs.Hosting.WebJobsStartupAttribute"); + + foreach (CustomAttribute attribute in attributes) + { + CustomAttributeArgument typeProperty = attribute.ConstructorArguments.ElementAtOrDefault(0); + CustomAttributeArgument nameProperty = attribute.ConstructorArguments.ElementAtOrDefault(1); + + TypeDefinition typeDef = (TypeDefinition)typeProperty.Value; + string assemblyQualifiedName = Assembly.CreateQualifiedName( + typeDef.Module.Assembly.FullName, GetReflectionFullName(typeDef)); + + string name = GetName((string)nameProperty.Value, typeDef); + + yield return new ExtensionReference + { + Name = name, + TypeName = assemblyQualifiedName, + HintPath = $@"{ExtensionsBinaryDirectoryPath}/{Path.GetFileName(fileName)}", + }; + } + } + private static string? GetAssemblyNameOrNull(string? typeName) { if (typeName == null) @@ -41,5 +73,33 @@ public static void AddHintPath(IEnumerable extensions) return null; } + + // Copying the WebJobsStartup constructor logic from: + // https://github.com/Azure/azure-webjobs-sdk/blob/e5417775bcb8c8d3d53698932ca8e4e265eac66d/src/Microsoft.Azure.WebJobs.Host/Hosting/WebJobsStartupAttribute.cs#L33-L47. + private static string GetName(string name, TypeDefinition startupTypeDef) + { + if (string.IsNullOrEmpty(name)) + { + // for a startup class named 'CustomConfigWebJobsStartup' or 'CustomConfigStartup', + // default to a name 'CustomConfig' + name = startupTypeDef.Name; + int idx = name.IndexOf("WebJobsStartup"); + if (idx < 0) + { + idx = name.IndexOf("Startup"); + } + if (idx > 0) + { + name = name.Substring(0, idx); + } + } + + return name; + } + + private static string GetReflectionFullName(TypeReference typeRef) + { + return typeRef.FullName.Replace("/", "+"); + } } } diff --git a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets index 40f57986..5b057d1b 100644 --- a/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets +++ b/sdk/Sdk/Targets/Microsoft.Azure.Functions.Worker.Sdk.targets @@ -10,11 +10,33 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and --> + + + <_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 + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\Managed.Functions\ + + + + + true + <_FunctionsExtensionsDirectory>.azurefunctions + <_FunctionsExtensionsJsonName>extensions.json + <_FunctionsWorkerConfigInputFile>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)\..\tools\worker.config.json)) + <_FunctionsMetadataLoaderExtensionFile>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll)) + <_FunctionsExtensionCommonProps>ImportDirectoryBuildProps=false;ImportDirectoryBuildTargets=false;ImportDirectoryPackagesProps=false + <_FunctionsExtensionRemoveProps>TargetFramework;RuntimeIdentifier;SelfContained;PublishSingleFile;PublishReadyToRun;UseCurrentRuntimeIdentifier;WebPublishMethod;PublishProfile;DeployOnBuild;PublishDir;OutDir;OutputPath; + + + - <_ToolingSuffix> <_DefaultAzureFunctionsVersion>v4 <_AzureFunctionsVersionNotSet Condition="'$(AzureFunctionsVersion)' == ''">true $(_DefaultAzureFunctionsVersion) + true + <_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 @@ -22,19 +44,6 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and <_ToolingSuffix Condition="$(AzureFunctionsVersion.StartsWith('v4',StringComparison.OrdinalIgnoreCase)) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And '$(TargetFrameworkVersion)' == 'v9.0'">net9-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 @@ -44,13 +53,13 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and true true - <_FunctionsGenerateExtensionProject Condition="'$(DesignTimeBuild)' != 'true'">true + <_FunctionsBuildEnabled Condition="'$(DesignTimeBuild)' != 'true'">true $(RootNamespace.Replace("-", "_")) <_FunctionsVersion Include="v3" InSupport="false" /> - <_FunctionsVersion Include="$(_DefaultAzureFunctionsVersion)" InSupport="true" /> + <_FunctionsVersion Include="v4" InSupport="true" /> @@ -61,23 +70,42 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and + + + $([System.IO.Path]::GetDirectoryName($(ExtensionsCsProj))) + $(IntermediateOutputPath)WorkerExtensions + $([System.IO.Path]::GetFullPath($(ExtensionsCsProjDirectory))) + $([System.IO.Path]::Combine($(ExtensionsCsProjDirectory), WorkerExtensions.csproj)) + + + + <_FunctionsMetadataPath>$(IntermediateOutputPath)functions.metadata + <_FunctionsWorkerConfigPath>$(IntermediateOutputPath)worker.config.json + + + - + <_AzureFunctionsVersionStandardized>$(AzureFunctionsVersion.ToLowerInvariant().Split('-')[0]) - true <_SelectedFunctionVersion Include="@(_FunctionsVersion)" Condition="'%(_FunctionsVersion.Identity)' == '$(_AzureFunctionsVersionStandardized)'" /> + + + + + + - - + + @@ -90,68 +118,72 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and + + + + DependsOnTargets="_WorkerExtensionsRestore;_WorkerExtensionsBuild" /> - - + + + + - - + + - <_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) + <_WorkerExtensionTarget>Build + <_WorkerExtensionTarget Condition="'$(FunctionsGenerateExtensionProject)' == 'false'">GetTargetPath + <_WorkerExtensionProperties Condition="'$(FunctionsGenerateExtensionProject)' == 'true'">Configuration=Release;$(_FunctionsExtensionCommonProps) + + + + + + + + <_FunctionsExtensionsOutputPath>$([System.IO.Path]::GetDirectoryName($(_WorkerExtensionsAssembly))) + <_FunctionsIntermediateExtensionJsonPath>$(_FunctionsExtensionsOutputPath)/bin/$(_FunctionsExtensionsJsonName) <_FunctionsIntermediateExtensionUpdatedJsonPath>$(IntermediateOutputPath)$(_FunctionsExtensionsJsonName) - - - - - - - - + + + DependsOnTargets="_FunctionsGenerateCommon;_FunctionsGenerateWorkerConfig" /> + + + <_TargetExtensionsCsProj Condition="'$(FunctionsGenerateExtensionProject)' == 'true'">$(ExtensionsCsProj) + + - - - - - @@ -171,27 +203,12 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and Overwrite="true" /> - - - - - - - - - - - + + OutputPath="$(_FunctionsIntermediateExtensionUpdatedJsonPath)" + AdditionalExtensions="$(_FunctionsMetadataLoaderExtensionFile)" /> - <_ExtensionBinaries Include="$(ExtensionsCsProjDirectory)\buildout\bin\**" - Exclude="$(ExtensionsCsProjDirectory)\buildout\bin\runtimes\**;$(_FunctionsIntermediateExtensionJsonPath)" - CopyToOutputDirectory="PreserveNewest" - CopyToPublishDirectory="PreserveNewest" /> - <_ExtensionRuntimeBinaries Include="$(ExtensionsCsProjDirectory)\buildout\runtimes\**" - CopyToOutputDirectory="PreserveNewest" - CopyToPublishDirectory="PreserveNewest" /> + <_ExtensionBinaries Include="$(_FunctionsExtensionsOutputPath)\bin\**" + Exclude="$(_FunctionsExtensionsOutputPath)\bin\runtimes\**;$(_FunctionsIntermediateExtensionJsonPath)" /> + <_ExtensionRuntimeBinaries Include="$(_FunctionsExtensionsOutputPath)\runtimes\**" /> - + - + - <_NoneWithTargetPath Include="@(_ExtensionFilesWithTargetPath)" TargetPath="$(_FunctionsExtensionsDirectory)/%(_ExtensionFilesWithTargetPath.TargetPath)" /> + <_FunctionsAdditionalFile Include="$(_FunctionsMetadataPath);$(_FunctionsWorkerConfigPath);$(_FunctionsIntermediateExtensionUpdatedJsonPath)" /> + <_FunctionsAdditionalFile Include="$(_FunctionsMetadataLoaderExtensionFile)" SubPath="$(_FunctionsExtensionsDirectory)/" /> + <_NoneWithTargetPath Include="@(_FunctionsAdditionalFile)" + TargetPath="%(_FunctionsAdditionalFile.SubPath)%(Filename)%(Extension)" + CopyToOutputDirectory="PreserveNewest" + CopyToPublishDirectory="PreserveNewest"/> + <_NoneWithTargetPath Include="@(_ExtensionFilesWithTargetPath)" + TargetPath="$(_FunctionsExtensionsDirectory)/%(_ExtensionFilesWithTargetPath.TargetPath)" + CopyToOutputDirectory="PreserveNewest" + CopyToPublishDirectory="PreserveNewest"/> - <_WorkerExtFilesToClean Include="$(ExtensionsCsProjDirectory)\**" Condition="'$(ExtensionsCsProjDirectory)' != ''" /> - <_WorkerExtFilesToClean Include="$(TargetDir)$(_FunctionsExtensionsDirectory)\**" /> + <_WorkerExtFilesToClean Include="$(ExtensionsCsProjDirectory)/**" Condition="'$(ExtensionsCsProjDirectory)' != '' AND '$(FunctionsGenerateExtensionProject)' == 'true'" /> + <_WorkerExtFilesToClean Include="$(TargetDir)$(_FunctionsExtensionsDirectory)/**" /> <_WorkerExtFilesToClean Include="$(_FunctionsMetadataPath)" /> <_WorkerExtFilesToClean Include="$(_FunctionsWorkerConfigPath)" /> <_WorkerExtFilesToClean Include="$(TargetDir)worker.config.json" /> @@ -239,10 +261,19 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and - + + + + + + + + + true + - \ No newline at end of file + diff --git a/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs b/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs index c76bb487..fa73090a 100644 --- a/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs +++ b/sdk/Sdk/Tasks/EnhanceExtensionsMetadata.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; @@ -24,12 +25,20 @@ public class EnhanceExtensionsMetadata : Task [Required] public string? OutputPath { get; set; } + [Required] + public ITaskItem[]? AdditionalExtensions { get; set; } + public override bool Execute() { string json = File.ReadAllText(ExtensionsJsonPath); - var extensionsMetadata = JsonSerializer.Deserialize(json); - ExtensionsMetadataEnhancer.AddHintPath(extensionsMetadata?.Extensions ?? Enumerable.Empty()); + var extensionsMetadata = JsonSerializer.Deserialize(json) ?? new ExtensionsMetadata(); + ExtensionsMetadataEnhancer.AddHintPath(extensionsMetadata.Extensions); + + foreach (ITaskItem item in AdditionalExtensions ?? Enumerable.Empty()) + { + extensionsMetadata.Extensions.AddRange(ExtensionsMetadataEnhancer.GetWebJobsExtensions(item.ItemSpec)); + } string newJson = JsonSerializer.Serialize(extensionsMetadata, _serializerOptions); File.WriteAllText(OutputPath, newJson); diff --git a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs index e8e42cee..e54aa995 100644 --- a/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs +++ b/sdk/Sdk/Tasks/GenerateFunctionMetadata.cs @@ -24,7 +24,6 @@ public class GenerateFunctionMetadata : Task [Required] public string? OutputPath { get; set; } - [Required] public string? ExtensionsCsProjFilePath { get; set; } [Required] @@ -45,12 +44,16 @@ public override bool Execute() { var functionGenerator = new FunctionMetadataGenerator(MSBuildLogger); - var functions = functionGenerator.GenerateFunctionMetadata(AssemblyPath!, ReferencePaths ?? Enumerable.Empty()); + IEnumerable functions = functionGenerator.GenerateFunctionMetadata(AssemblyPath!, ReferencePaths ?? Enumerable.Empty()); + IDictionary extensions = functionGenerator.Extensions; - var extensions = functionGenerator.Extensions; - var extensionsCsProjGenerator = new ExtensionsCsprojGenerator(extensions, ExtensionsCsProjFilePath!, AzureFunctionsVersion!, TargetFrameworkIdentifier!, TargetFrameworkVersion!); + if (!string.IsNullOrEmpty(ExtensionsCsProjFilePath)) + { + // Null/empty ExtensionsCsProjFilePath means the extension project is externally provided. + var extensionsCsProjGenerator = new ExtensionsCsprojGenerator(extensions, ExtensionsCsProjFilePath!, AzureFunctionsVersion!, TargetFrameworkIdentifier!, TargetFrameworkVersion!); + extensionsCsProjGenerator.Generate(); + } - extensionsCsProjGenerator.Generate(); WriteMetadataWithRetry(functions); } catch (FunctionsMetadataGenerationException) diff --git a/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs b/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs index 6576e99d..16d269f9 100644 --- a/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs +++ b/test/FunctionMetadataGeneratorTests/ExtensionsCsProjGeneratorTests.cs @@ -33,20 +33,19 @@ public void GetCsProjContent_Succeeds(FuncVersion version) [InlineData(FuncVersion.V4)] public void GetCsProjContent_IncrementalSupport(FuncVersion version) { - DateTime RunGenerate(string subPath, out string contents) + DateTime RunGenerate(string project, out string contents) { - var generator = GetGenerator(version, subPath); + var generator = GetGenerator(version, project); generator.Generate(); - string path = Path.Combine(subPath, ExtensionsCsprojGenerator.ExtensionsProjectName); - contents = File.ReadAllText(path); - var csproj = new FileInfo(Path.Combine(subPath, ExtensionsCsprojGenerator.ExtensionsProjectName)); + contents = File.ReadAllText(project); + var csproj = new FileInfo(project); return csproj.LastWriteTimeUtc; } - string subPath = Guid.NewGuid().ToString(); - DateTime firstRun = RunGenerate(subPath, out string first); - DateTime secondRun = RunGenerate(subPath, out string second); + string project = Path.Combine(Guid.NewGuid().ToString(), "TestExtension.csproj"); + DateTime firstRun = RunGenerate(project, out string first); + DateTime secondRun = RunGenerate(project, out string second); Assert.NotEqual(firstRun, secondRun); Assert.Equal(first, second); diff --git a/test/SdkE2ETests/InnerBuildTests.cs b/test/SdkE2ETests/InnerBuildTests.cs index 1f993bd2..3d271f99 100644 --- a/test/SdkE2ETests/InnerBuildTests.cs +++ b/test/SdkE2ETests/InnerBuildTests.cs @@ -33,11 +33,6 @@ public async Task Build_ScansReferences() JToken extensionsJsonContents = JObject.Parse(File.ReadAllText(extensionsJsonPath)); JToken expectedExtensionsJson = JObject.Parse(@"{ ""extensions"": [ - { - ""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"" - }, { ""name"": ""AzureStorageBlobs"", ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageBlobsWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Blobs, Version=5.3.1.0, Culture=neutral, PublicKeyToken=92742159e12e44c8"", @@ -47,7 +42,12 @@ public async Task Build_ScansReferences() ""name"": ""AzureStorageQueues"", ""typeName"": ""Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageQueuesWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Queues, Version=5.1.3.0, Culture=neutral, PublicKeyToken=92742159e12e44c8"", ""hintPath"": ""./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.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"" + }, ] }"); diff --git a/test/SdkE2ETests/PublishTests.cs b/test/SdkE2ETests/PublishTests.cs index 5a7a7692..10b50f39 100644 --- a/test/SdkE2ETests/PublishTests.cs +++ b/test/SdkE2ETests/PublishTests.cs @@ -88,15 +88,15 @@ private async Task RunPublishTest(string outputDir, string additionalParams = nu { extensions = new[] { - new Extension("Startup", - "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.Startup, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c", - @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll"), new Extension("AzureStorageBlobs", "Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageBlobsWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Blobs, Version=5.3.1.0, Culture=neutral, PublicKeyToken=92742159e12e44c8", @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Blobs.dll"), new Extension("AzureStorageQueues", "Microsoft.Azure.WebJobs.Extensions.Storage.AzureStorageQueuesWebJobsStartup, Microsoft.Azure.WebJobs.Extensions.Storage.Queues, Version=5.3.1.0, Culture=neutral, PublicKeyToken=92742159e12e44c8", - @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.dll") + @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.Storage.Queues.dll"), + new Extension("Startup", + "Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.Startup, Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=551316b6919f366c", + @"./.azurefunctions/Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll"), } }); Assert.True(JToken.DeepEquals(extensionsJsonContents, expected), $"Actual: {extensionsJsonContents}{Environment.NewLine}Expected: {expected}");