Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement SupportsDeferredBindingAttribute #1275

Merged
merged 3 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,16 @@ public class ExtensionInformationAttribute : Attribute

public bool EnableImplicitRegistration { get; }

public bool SupportsDeferredBinding { get; }

public ExtensionInformationAttribute(string extensionPackage, string extensionVersion)
: this(extensionPackage, extensionVersion, false, false)
: this(extensionPackage, extensionVersion, false)
{
}

public ExtensionInformationAttribute(string extensionPackage, string extensionVersion, bool enableImplicitRegistration)
: this(extensionPackage, extensionVersion, enableImplicitRegistration, false)
{
}

public ExtensionInformationAttribute(string extensionPackage, string extensionVersion, bool enableImplicitRegistration, bool supportsDeferredBinding)
liliankasem marked this conversation as resolved.
Show resolved Hide resolved
{
ExtensionPackage = extensionPackage;
ExtensionVersion = extensionVersion;
EnableImplicitRegistration = enableImplicitRegistration;
SupportsDeferredBinding = supportsDeferredBinding;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;

namespace Microsoft.Azure.Functions.Worker.Extensions.Abstractions
{
/// <summary>
/// Specifies if a binding attribute supports deferred binding when generating function metadata.
/// This is to be used on input, output or trigger attributes that support deferred binding.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class SupportsDeferredBindingAttribute : Attribute
liliankasem marked this conversation as resolved.
Show resolved Hide resolved
{
}
}
1 change: 1 addition & 0 deletions sdk/Sdk/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal static class Constants
internal const string FixedDelayRetryAttributeType = "Microsoft.Azure.Functions.Worker.FixedDelayRetryAttribute";
internal const string ExponentialBackoffRetryAttributeType = "Microsoft.Azure.Functions.Worker.ExponentialBackoffRetryAttribute";
internal const string BindingPropertyNameAttributeType = "Microsoft.Azure.Functions.Worker.Extensions.Abstractions.BindingPropertyNameAttribute";
internal const string SupportsDeferredBindingAttributeType = "Microsoft.Azure.Functions.Worker.Extensions.Abstractions.SupportsDeferredBindingAttribute";

// System types
internal const string IEnumerableType = "System.Collections.IEnumerable";
Expand Down
46 changes: 25 additions & 21 deletions sdk/Sdk/FunctionMetadataGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Mono.Cecil;
using Mono.Collections.Generic;

namespace Microsoft.Azure.Functions.Worker.Sdk
{
Expand Down Expand Up @@ -120,7 +118,7 @@ internal IEnumerable<SdkFunctionMetadata> GenerateFunctionMetadata(ModuleDefinit
functions.AddRange(functionsResult);
}

if (!moduleExtensionRegistered && TryAddExtensionInfo(_extensions, module.Assembly, out bool supportsDeferredBinding, usedByFunction: false))
if (!moduleExtensionRegistered && TryAddExtensionInfo(_extensions, module.Assembly, usedByFunction: false))
{
_logger.LogMessage($"Implicitly registered {module.FileName} as an extension.");
}
Expand Down Expand Up @@ -347,7 +345,7 @@ private void AddOutputBindingFromProperty(IList<ExpandoObject> bindingMetadata,
foundOutputAttribute = true;

AddOutputBindingMetadata(bindingMetadata, propertyAttribute, property.PropertyType, property.Name);
AddExtensionInfo(_extensions, propertyAttribute, out bool supportsDeferredBinding);
AddExtensionInfo(_extensions, propertyAttribute);
}
}
}
Expand All @@ -367,7 +365,7 @@ private bool TryAddOutputBindingFromMethod(IList<ExpandoObject> bindingMetadata,
}

AddOutputBindingMetadata(bindingMetadata, methodAttribute, methodAttribute.AttributeType, Constants.ReturnBindingName);
AddExtensionInfo(_extensions, methodAttribute, out bool supportsDeferredBinding);
AddExtensionInfo(_extensions, methodAttribute);

foundBinding = true;
}
Expand All @@ -384,8 +382,8 @@ private void AddInputTriggerBindingsAndExtensions(IList<ExpandoObject> bindingMe
{
if (IsFunctionBindingType(parameterAttribute))
{
AddExtensionInfo(_extensions, parameterAttribute, out bool supportsDeferredBinding);
AddBindingMetadata(bindingMetadata, parameterAttribute, parameter.ParameterType, parameter.Name, supportsDeferredBinding);
AddExtensionInfo(_extensions, parameterAttribute);
AddBindingMetadata(bindingMetadata, parameterAttribute, parameter.ParameterType, parameter.Name);
}
}
}
Expand Down Expand Up @@ -416,10 +414,10 @@ private static void AddOutputBindingMetadata(IList<ExpandoObject> bindingMetadat
AddBindingMetadata(bindingMetadata, attribute, parameterType, parameterName: name);
}

private static void AddBindingMetadata(IList<ExpandoObject> bindingMetadata, CustomAttribute attribute, TypeReference parameterType, string? parameterName, bool supportsReferenceType = false)
private static void AddBindingMetadata(IList<ExpandoObject> bindingMetadata, CustomAttribute attribute, TypeReference parameterType, string? parameterName)
{
string bindingType = GetBindingType(attribute);
ExpandoObject binding = BuildBindingMetadataFromAttribute(attribute, bindingType, parameterType, parameterName, supportsReferenceType);
ExpandoObject binding = BuildBindingMetadataFromAttribute(attribute, bindingType, parameterType, parameterName);
bindingMetadata.Add(binding);
}

Expand Down Expand Up @@ -471,7 +469,7 @@ private static void AddBindingMetadata(IList<ExpandoObject> bindingMetadata, Cus
return bindingNameAliasMap;
}

private static ExpandoObject BuildBindingMetadataFromAttribute(CustomAttribute attribute, string bindingType, TypeReference parameterType, string? parameterName, bool supportsDeferredBinding)
private static ExpandoObject BuildBindingMetadataFromAttribute(CustomAttribute attribute, string bindingType, TypeReference parameterType, string? parameterName)
{
ExpandoObject binding = new ExpandoObject();

Expand All @@ -489,7 +487,7 @@ private static ExpandoObject BuildBindingMetadataFromAttribute(CustomAttribute a

// For extensions that support deferred binding, set the supportsDeferredBinding property so parameters are bound by the worker
// Only use deferred binding for input and trigger bindings, output is out not currently supported
if (supportsDeferredBinding && direction != Constants.OutputBindingDirection)
if (SupportsDeferredBinding(attribute) && direction != Constants.OutputBindingDirection)
liliankasem marked this conversation as resolved.
Show resolved Hide resolved
{
bindingProperties.Add(Constants.SupportsDeferredBindingProperty, Boolean.TrueString);
}
Expand Down Expand Up @@ -752,16 +750,14 @@ private static void AddHttpOutputBinding(IList<ExpandoObject> bindingMetadata, s
bindingMetadata.Add((ExpandoObject)returnBinding);
}

private static void AddExtensionInfo(IDictionary<string, string> extensions, CustomAttribute attribute, out bool supportsDeferredBinding)
private static void AddExtensionInfo(IDictionary<string, string> extensions, CustomAttribute attribute)
{
AssemblyDefinition extensionAssemblyDefinition = attribute.AttributeType.Resolve().Module.Assembly;
TryAddExtensionInfo(extensions, extensionAssemblyDefinition, out supportsDeferredBinding);
TryAddExtensionInfo(extensions, extensionAssemblyDefinition);
}

private static bool TryAddExtensionInfo(IDictionary<string, string> extensions, AssemblyDefinition extensionAssemblyDefinition, out bool supportsDeferredBinding, bool usedByFunction = true)
private static bool TryAddExtensionInfo(IDictionary<string, string> extensions, AssemblyDefinition extensionAssemblyDefinition, bool usedByFunction = true)
{
supportsDeferredBinding = false;

foreach (var assemblyAttribute in extensionAssemblyDefinition.CustomAttributes)
{
if (string.Equals(assemblyAttribute.AttributeType.FullName, Constants.ExtensionsInformationType, StringComparison.Ordinal))
Expand All @@ -775,11 +771,6 @@ private static bool TryAddExtensionInfo(IDictionary<string, string> extensions,
// EnableImplicitRegistration
implicitlyRegister = (bool)assemblyAttribute.ConstructorArguments[2].Value;
}

if (assemblyAttribute.ConstructorArguments.Count >= 4)
{
supportsDeferredBinding = (bool)assemblyAttribute.ConstructorArguments[3].Value;
}

if (usedByFunction || implicitlyRegister)
{
Expand All @@ -804,6 +795,19 @@ private static string GetBindingDirection(CustomAttribute attribute)
return Constants.InputBindingDirection;
}

private static bool SupportsDeferredBinding(CustomAttribute attribute)
{
var typeDefinition = attribute?.AttributeType?.Resolve();

if (typeDefinition is null)
{
return false;
}

return typeDefinition.CustomAttributes
.Any(a => string.Equals(a.AttributeType.FullName, Constants.SupportsDeferredBindingAttributeType, StringComparison.Ordinal));
}

private static bool IsOutputBindingType(CustomAttribute attribute)
{
return TryGetBaseAttributeType(attribute, Constants.OutputBindingType, out _);
Expand Down