azure-functions-host: routePrefix ignored when using ConfigurationBuilder

In WebJobsStartup, if merging original configuration with custom configuration, the routePrefix defined in host.json is ignored and all HttpTrigger functions use “api” as routePrefix

I have not deployed this to any Azure resource yet, and I’m only running locally, so please bear with the lack of investigative information

Investigative information

Please provide the following:

  • Timestamp: 2019-04-30
  • Function App version: 2.0
  • Function App name: N/A
  • Function name(s) (as appropriate): N/A
  • Invocation ID: N/A
  • Region: N/A

Repro steps

Use the following code in a WebJobsStartup to add support for custom config-files

[assembly: WebJobsStartup(typeof(Startup))]
namespace MyFuncApp {
    public class Startup : IWebJobsStartup {
        public void Configure(IWebJobsBuilder builder)
        {
            //Get the current config and merge it into a new ConfigurationBuilder to keep the old settings
            ConfigurationBuilder configBuilder = new ConfigurationBuilder();
            var descriptor = builder.Services.FirstOrDefault(d => d.ServiceType == typeof(IConfiguration));
            if (descriptor?.ImplementationInstance is IConfigurationRoot configuration)
            {
                configBuilder.AddConfiguration(configuration);
            }

            IConfigurationRoot config = configBuilder.Build();

            //replace the existing config with the new one
            builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), config));
    }
}

This should use the existing configurations inside a new ConfigurationBuilder. I could now add .AddJsonFile(...) if I wanted to, however for this example I’ve just created a new ConfigurationBuilder, copied the existing config into this builder, created a new config object from this builder, and replace the old config object with the new one, so there are no custom configurations to override anything.

If I debug I can see that the config variable contains a (private) ChainedConfigurationProvider that contains all the default configurations, including the HostJsonFileConfigurationProvider that has routePrefix: "".

When starting the Function app locally I can see that the routePrefix is now ignored, and all my functions have “api” at the start of their route, even though my host.json has a blank value. Here’s my host.json:

{
  "version": "2.0",
  "extensions": {
    "http": {
      "routePrefix": ""
    }
  }
}

It all boils down to this line of code:

builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), config));

If I remove this the routePrefix is blank (as stated in the host.json file). If this line is used the routePrefix is “api”.

It would therefore seem that there might be a bug in the routePrefix resolver that fails to read the prefix from host.json whenever a custom IConfiguration is used, even if this configuration should have merged in the settings from the old configuration.

Expected behavior

Configurations should be merged without overwriting routePrefix functionality

Actual behavior

routePrefix gets reset to "api" even if it is "" in host.json

Known workarounds

N/A

Related information

  • Obviously coded in C#
  • HttpBindings

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 5
  • Comments: 20 (4 by maintainers)

Most upvoted comments

The workaround mentioned by @xperiandri seemed to do the trick for now. I added the the following line to to the Startup.cs:

services.Configure<HttpOptions>(options => options.RoutePrefix = string.Empty);

It is half of 2023…

What I seem to have observed in testing this out is that the value specified in host.json using the above approach is obeyed if you use a value other than "". Example, I set it to "foo" and my routes were discovered with a routePrefix of /foo. There seems to be something about empty string specifically.

same issue as @nadershamma with a v4 function. Honestly if it’s been 2 years and multiple function app versions, I am not hopefully that MS will take this issue seriously.

the most annoying part is that if I deploy using the func azure functionapp publish command, it properly sets the api route from /api to /api/whatever but when I deploy in azure devops, it always ignores my host.json file and sets it to /api. Tremendously frustrating.

Has anyone found a way to get the route prefix set through azure devops? Here’s my yaml for doing the deployment to my function app slot.

- task: AzureFunctionApp@1
            displayName: 'Azure functions app deploy'
            inputs:
              azureSubscription: $(azureSubscription)
              appType: functionApp
              appName: $(functionAppName)
              slotName: $(slotName)
              package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'

Woked around with .Configure<HttpOptions>(fun (options : HttpOptions) -> options.RoutePrefix <- String.Empty; ()) for now. But it is weird

@gthvidsten as a workaround you can do the following in the startup:

IServiceProvider provider = builder.Services.BuildServiceProvider();
IConfiguration existingConfig = provider.GetRequiredService<IConfiguration>();
var yourBuilder = new ConfigurationBuilder().AddConfiguration(existingConfiguration);//add your providers as needed
services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), yourBuilder.Build()));

This works for functions runtime V3, tested both locally and in the cloud.