Azure / azure-webjobs-sdk

Azure WebJobs SDK
MIT License
739 stars 358 forks source link

Azure Function Isolated Mode. Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions....'. Microsoft.Azure.WebJobs.Host: '%Azure:ServiceBus:Queue%' does not resolve to a value. #3070

Open textbytext opened 7 months ago

textbytext commented 7 months ago

Azure Function Isolated Mode.

Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions....'. Microsoft.Azure.WebJobs.Host: '%KEY:NAME%' does not resolve to a value.

My configuration:

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
...
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />        
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.EventGrid" Version="3.4.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="5.17.0" />

Usage:

[Function("Function-Name")]
public async Task Run(
    [ServiceBusTrigger(
        queueName: "%Azure:ServiceBus:Queue%",
        Connection = "SERVICEBUS:CONNECTION:STRING")]
    ServiceBusReceivedMessage message,
    ServiceBusMessageActions messageActions,
    CancellationToken cancellationToken)
{
   ...
}

"%Azure:ServiceBus:Queue%" and "SERVICEBUS:CONNECTION:STRING" are taking from an AzureKeyVault (HostBuilder config)

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureHostConfiguration(builder =>
    {
        builder.AddAzureKeyVaultSettingsConfiguration(GetKeyVaultName());
    })
    .ConfigureServices(services =>
    {
        ...
    })
    .Build();

Error: Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.Function-Name'. Microsoft.Azure.WebJobs.Host: '%Azure:ServiceBus:Queue%' does not resolve to a value.

My assumption: The problem is in the FunctionIndexProvider.cs file.

FunctionIndexer indexer = new FunctionIndexer(_triggerBindingProvider, 
...
_instanceServicesFactory, 
null, 
_sharedQueue, 
...
_defaultRetryStrategy); 

The INameResolver does not passing (null instead) to the constructor.

eriktack commented 7 months ago

I can only get my function app to read %somevalue% in a queue trigger if it is set as an environment variable after switching to isolated mode. If it is set in appsettings.json its ignored and I get the same error as you get.

It seems like whatever INameResolver is used in Microsoft.Azure.WebJobs.Host.NameResolverExtensions.ResolveWholeStringCore when configuring %%-values is only able to read environment variables.

Note: In the application, if i inject IConfiguration anywhere, it has all values from appsettings.json.

fhurta commented 4 months ago

I was hunting this issue as well - after migration from net6 InProc to net8 Isolated, none of the Functions with timer trigger using the %% syntax started.

It's a nasty regression, we have around 20 functions with reasonable defaults in appsettings.json. In TEST env we used to override it in AppService App Settings to execute more often so we don't have to wait during the testing but in higher environments we only override when troubleshooting..

So now just to get it up and running we need to pollute the AppService with all these settings..

JimmyJonesJr commented 4 months ago

Just ran into this issue as well. Have to say isolated functions lacks support for a LOT of seemingly basic features like this... Guess I'll just jam in an App Settings for now.

AlbertKw commented 3 months ago

I had the same issue after migration from .net 6 in-process to .net 8 isolated. I use also the timer trigger with the %% syntax and it wasn't working. I moved my cron settings in local.settings.json to "Values" section and it works as before.

local.settings.json:

"Values": {
  "AzureWebJobsStorage": "UseDevelopmentStorage=true",
  "FUNCTIONS_WORKER_RUNTIME": "botnet-isolated",
  "MyFuncTrigger": "*/5 * * * *" -- moved here and works now
}
jonathan-vogel-siemens commented 3 weeks ago

I am also having this exact issue - the isolated model is not really usable right now in a production environment. The docs look the same for a couple of months and the bug does not seem to be fixed at all, very sad :(

Amelsfort commented 2 weeks ago

I also had this issue. I created a workaround by creating a custom FunctionMetadataProvider and replacing the values in the RawBindings:

public class CustomFunctionMetadataProvider : IFunctionMetadataProvider
{
    private readonly IServiceProvider _serviceProvider;
    private readonly IConfiguration _configuration;

    public CustomFunctionMetadataProvider(IServiceProvider serviceProvider, IConfiguration configuration)
    {
        _serviceProvider = serviceProvider;
        _configuration = configuration;
    }

    public Task<ImmutableArray<IFunctionMetadata>> GetFunctionMetadataAsync(string directory)
    {
        var service = _serviceProvider.GetServices<IFunctionMetadataProvider>().ToList();
        var functionMetadataProvider = service.Last(x => x.GetType() != typeof(CustomFunctionMetadataProvider));
        var metadataList = new List<IFunctionMetadata>();
        Task<ImmutableArray<IFunctionMetadata>> list = functionMetadataProvider.GetFunctionMetadataAsync(directory);

        var settingRegex = new Regex("%(.+?)%");
        foreach (var item in list.Result)
        {
            for (var i=0; i < item.RawBindings.Count; i++)
            {
                var binding = item.RawBindings[i];
                var value = settingRegex.Replace(binding, m =>
                {
                    var key = m.Groups[1].Value;
                    return _configuration[key];
                });
                item.RawBindings[i] = value;
            }
            metadataList.Add(item);
        }

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