Skip to content

Commit

Permalink
BugFix-FunctionMetadataProvider emits incorrect binding name property…
Browse files Browse the repository at this point in the history
… value for async functions (#1851)

* Fixing 1817 - FunctionMetadataProvider emits incorrect binding name property value for async functions

* Add release notes
  • Loading branch information
kshyju authored Aug 23, 2023
1 parent ddfdc35 commit 9917849
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -432,10 +432,10 @@ private bool TryGetReturnTypeBindings(MethodDeclarationSyntax method, SemanticMo
}

if (!SymbolEqualityComparer.Default.Equals(returnTypeSymbol, _knownTypes.VoidType) &&
!SymbolEqualityComparer.Default.Equals(returnTypeSymbol, _knownTypes.TaskType))
!SymbolEqualityComparer.Default.Equals(returnTypeSymbol.OriginalDefinition, _knownTypes.TaskType))
{
// If there is a Task<T> return type, inspect T, the inner type.
if (SymbolEqualityComparer.Default.Equals(returnTypeSymbol, _knownTypes.TaskOfTType))
if (SymbolEqualityComparer.Default.Equals(returnTypeSymbol.OriginalDefinition, _knownTypes.TaskOfTType))
{
GenericNameSyntax genericSyntax = (GenericNameSyntax)returnTypeSyntax;
var innerTypeSyntax = genericSyntax.TypeArgumentList.Arguments.First(); // Generic task should only have one type argument
Expand Down
3 changes: 2 additions & 1 deletion sdk/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@

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

- Updated source generated versions of FunctionExecutor to use `global::` namespace prefix to avoid ambiguity between namespaces.(#1847)
- Updated source generated versions of FunctionExecutor to use `global::` namespace prefix to avoid ambiguity between namespaces.(#1847)
- Fixing the check to determine the function return type for async functions.(#1817)
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ public Task<ImmutableArray<IFunctionMetadata>> GetFunctionMetadataAsync(string d
var metadataList = new List<IFunctionMetadata>();
var Function0RawBindings = new List<string>();
Function0RawBindings.Add(@"{""name"":""myReq"",""type"":""HttpTrigger"",""direction"":""In"",""authLevel"":""Admin"",""methods"":[""get"",""Post""],""route"":""/api2""}");
Function0RawBindings.Add(@"{""name"":""Result"",""type"":""http"",""direction"":""Out""}");
Function0RawBindings.Add(@"{""name"":""$return"",""type"":""http"",""direction"":""Out""}");

var Function0 = new DefaultFunctionMetadata
{
Expand Down Expand Up @@ -526,6 +526,127 @@ await TestHelpers.RunTestAsync<FunctionMetadataProviderGenerator>(
expectedGeneratedFileName,
expectedOutput);
}

[Fact]
public async Task GenerateMultipleFunctionsMetadataTest()
{
string inputCode = """
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;

namespace FunctionApp
{
public class HttpTriggerSimple
{
[Function(nameof(Run))]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req, FunctionContext executionContext)
{
throw new NotImplementedException();
}
[Function(nameof(RunAsync))]
public Task<HttpResponseData> RunAsync([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
throw new NotImplementedException();
}
[Function(nameof(RunAsync2))]
public async Task<HttpResponseData> RunAsync2([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
throw new NotImplementedException();
}
}
}
""";

string expectedGeneratedFileName = $"GeneratedFunctionMetadataProvider.g.cs";
string expectedOutput = """
// <auto-generated/>
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker.Core.FunctionMetadata;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Microsoft.Azure.Functions.Worker
{
public class GeneratedFunctionMetadataProvider : IFunctionMetadataProvider
{
public Task<ImmutableArray<IFunctionMetadata>> GetFunctionMetadataAsync(string directory)
{
var metadataList = new List<IFunctionMetadata>();
var Function0RawBindings = new List<string>();
Function0RawBindings.Add(@"{""name"":""req"",""type"":""HttpTrigger"",""direction"":""In"",""authLevel"":""Anonymous"",""methods"":[""get"",""post""]}");
Function0RawBindings.Add(@"{""name"":""$return"",""type"":""http"",""direction"":""Out""}");

var Function0 = new DefaultFunctionMetadata
{
Language = "dotnet-isolated",
Name = "Run",
EntryPoint = "FunctionApp.HttpTriggerSimple.Run",
RawBindings = Function0RawBindings,
ScriptFile = "TestProject.dll"
};
metadataList.Add(Function0);
var Function1RawBindings = new List<string>();
Function1RawBindings.Add(@"{""name"":""req"",""type"":""HttpTrigger"",""direction"":""In"",""authLevel"":""Anonymous"",""methods"":[""get"",""post""]}");
Function1RawBindings.Add(@"{""name"":""$return"",""type"":""http"",""direction"":""Out""}");

var Function1 = new DefaultFunctionMetadata
{
Language = "dotnet-isolated",
Name = "RunAsync",
EntryPoint = "FunctionApp.HttpTriggerSimple.RunAsync",
RawBindings = Function1RawBindings,
ScriptFile = "TestProject.dll"
};
metadataList.Add(Function1);
var Function2RawBindings = new List<string>();
Function2RawBindings.Add(@"{""name"":""req"",""type"":""HttpTrigger"",""direction"":""In"",""authLevel"":""Anonymous"",""methods"":[""get"",""post""]}");
Function2RawBindings.Add(@"{""name"":""$return"",""type"":""http"",""direction"":""Out""}");

var Function2 = new DefaultFunctionMetadata
{
Language = "dotnet-isolated",
Name = "RunAsync2",
EntryPoint = "FunctionApp.HttpTriggerSimple.RunAsync2",
RawBindings = Function2RawBindings,
ScriptFile = "TestProject.dll"
};
metadataList.Add(Function2);

return Task.FromResult(metadataList.ToImmutableArray());
}
}

public static class WorkerHostBuilderFunctionMetadataProviderExtension
{
///<summary>
/// Adds the GeneratedFunctionMetadataProvider to the service collection.
/// During initialization, the worker will return generated function metadata instead of relying on the Azure Functions host for function indexing.
///</summary>
public static IHostBuilder ConfigureGeneratedFunctionMetadataProvider(this IHostBuilder builder)
{
builder.ConfigureServices(s =>
{
s.AddSingleton<IFunctionMetadataProvider, GeneratedFunctionMetadataProvider>();
});
return builder;
}
}
}
""";

await TestHelpers.RunTestAsync<FunctionMetadataProviderGenerator>(
_referencedExtensionAssemblies,
inputCode,
expectedGeneratedFileName,
expectedOutput);
}
}
}
}

0 comments on commit 9917849

Please sign in to comment.