Jonathan Stanton
Jonathan Stanton

Reputation: 2630

Azure Functions - Trigger Variables - Isolated Functions

In Azure Functions you can use the nomenclature of %token% to have at runtime that token being replaced by an Environment Variable. e.g.

 public Task FunctionName(
     [ServiceBusTrigger("%MessageTopic%",
         "%MessageSubscription%",
         Connection = "ConnectionString")]
     ServiceBusReceivedMessage message,
     [DurableClient] DurableTaskClient durableOrchestrationClient)

Before Isolated Functions you could create an implementation of INameResolver to allow you to perform your own lookup and replacement of these tokens.

In Isolated Functions INameProvider no longer exists.

How can you perform this same functionality?

Upvotes: 1

Views: 635

Answers (1)

Jonathan Stanton
Jonathan Stanton

Reputation: 2630

From what I can see the resolving of the %token% value from Environment variables is done in Func.exe / the Host in Azure Functions.

The Metadata that is needed for the runner to register with all the queue etc is sent across via a GRPC call on start up.

This metadata is generated at design time by a Code Generator and is in a class which implements IFunctionMetadataProvider.

I have been able to create a new class that implements decorate the actual code generated class that generates the metadata:

internal class ConfigurableFunctionMetadataProvider(IFunctionMetadataProvider baseProvider, IConfiguration configuration, ILogger<ConfigurableFunctionMetadataProvider> logger) : IFunctionMetadataProvider
{
  private static readonly Regex RegexExpression = new Regex("%([^%\"]*)%", RegexOptions.Compiled, TimeSpan.FromSeconds(5));
  public Task<ImmutableArray<IFunctionMetadata>> GetFunctionMetadataAsync(string directory) =>
    baseProvider.GetFunctionMetadataAsync(directory).ContinueWith(task =>
    {
      var functionMetadataArray = task.Result;
      foreach (var metadata in functionMetadataArray)
      {
        for (int i = 0; i < metadata.RawBindings.Count; i++)
        {
          Match matchResults = RegexExpression.Match(metadata.RawBindings[i]);
          while (matchResults.Success)
          {
            var replacement = configuration.GetValue<string>(matchResults.Groups[1].Value);
            if (replacement != null)
            {
              logger.LogInformation("Replacing token '{TokenName}' in '{FunctionName}' with '{Value}'", matchResults.Groups[0].Value, metadata.Name, replacement);
              metadata.RawBindings[i] = metadata.RawBindings[i].Replace(matchResults.Groups[0].Value, replacement);
            }

            matchResults = matchResults.NextMatch();
          }
        }
      }

      return functionMetadataArray;
    });
}

Then where you declare your dependency injection add the following line (using scrutor from nuget):

services.Decorate<IFunctionMetadataProvider, ConfigurableFunctionMetadataProvider>();

The code will also log out the fact it has made a substitution.

Upvotes: 4

Related Questions