Azure / azure-webjobs-sdk

Azure WebJobs SDK
MIT License
739 stars 358 forks source link

Exception when using ConfigurationBuilder with Durable Functions #2059

Open coreConvention opened 5 years ago

coreConvention commented 5 years ago

This seems like such an odd error, and it may not be a bug. But was hindering something I was trying to do with IServicesCollection so I was hoping someone might know whats going on. I am attempting to use a ServiceBusTrigger with a Durable function. I am using an implementation of IWebJobsStartup to do my registrations. I had originally approached this the same way I do with normal functions; I instantiate an instance of ConfigurationBuilder in the configure method of my IWebJobsStartup implementation and pass my config instance to a function where I register all my services.

public void Configure(IWebJobsBuilder builder)
{
    var config = new ConfigurationBuilder()
        .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
        .AddEnvironmentVariables()
        .Build();
    RegisterServices(builder.Services, config);
    builder.AddExtension<InjectConfiguration>();
}

One registration in particular requires the ConfigurationBuilder to resolve connection string through an instance of IConfiguration:

services.AddSingleton<IContextProvider<ValidationContext>>(sp =>
{
    return new ContextProvider<ValidationContext>(config.GetValue<string>("ContextConnectionString"));
});

This worked great with normal functions but a couple weird things happen with durable functions. The first was an error:

Microsoft.Azure.WebJobs.ServiceBus: Method not found: 'Microsoft.Azure.WebJobs.IWebJobsExtensionBuilder Microsoft.Azure.WebJobs.WebJobsExtensionBuilderExtensions.ConfigureOptions(Microsoft.Azure.WebJobs.IWebJobsExtensionBuilder, System.Action`3<Microsoft.Extensions.Configuration.IConfiguration,System.String,!!0>)'.

Which oddly enough seemed to happen even if I wasn't using the instance of configurationbuilder anywhere. Its very existance seems to cause this error. Even just having "var config = new ConfigurationBuilder().Build();" in there but not using it would cause this error. Deleting it resolves that issue. Weird. This happens when it calls builder.AddServiceBus(p => { }) in ServiceBusWebJobsBuilderExtensions.cs in the service bus extensions. The stack trace is at the bottom of this issue.

I remove the var config = new ConfigurationBuilder()...Build(); stuff from IWebJobsStartup it just magically starts working. Again this happens whether I use "config" or not.

So anyway I removed that assuming maybe it was interfering with something in the service bus extensions, and tried to just resolve IConfiguration from the service provider in my registration:

services.AddSingleton<IContextProvider<ValidationContext>>(sp =>
{
    var config = sp.GetService<IConfiguration>();               
    return new ContextProvider<ValidationContext>(config.GetValue<string>("ContextConnectionString"));
});

...at which point I get an error saying it could not resolve IConfiguration. Doh! So I just removed the connection string from the constructor in ContextProvider and attempted to resolve IConfiguration instead, but it seems I cannot resolve IConfiguration from anywhere in the app either, even when the rest of it is working. Am I missing something here? How can I use IConfiguration in durable functions with IConfiguration?

Stack Trace:
   at Microsoft.Extensions.Hosting.ServiceBusHostBuilderExtensions.AddServiceBus(IWebJobsBuilder builder, Action`1 configure)
   at Microsoft.Extensions.Hosting.ServiceBusHostBuilderExtensions.AddServiceBus(IWebJobsBuilder builder) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Extensions.ServiceBus\Config\ServiceBusWebJobsBuilderExtensions.cs:line 23
   at Microsoft.Azure.WebJobs.ServiceBus.ServiceBusWebJobsStartup.Configure(IWebJobsBuilder builder) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Extensions.ServiceBus\ServiceBusWebJobsStartup.cs:line 16
   at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.UseWebJobsStartup(IWebJobsBuilder builder, Type startupType) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs:line 72
   at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.UseExternalStartup(IWebJobsBuilder builder, IWebJobsStartupTypeLocator startupTypeLocator) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs:line 103
   at Microsoft.Azure.WebJobs.Script.ScriptHostBuilderExtensions.UseScriptExternalStartup(IWebJobsBuilder builder, String rootScriptPath) in C:\azure-webjobs-sdk-script\src\WebJobs.Script\ScriptHostBuilderExtensions.cs:line 182
   at Microsoft.Azure.WebJobs.Script.ScriptHostBuilderExtensions.<>c__DisplayClass3_0.<AddScriptHostCore>b__0(IWebJobsBuilder webJobsBuilder) in C:\azure-webjobs-sdk-script\src\WebJobs.Script\ScriptHostBuilderExtensions.cs:line 107
   at Microsoft.Extensions.Hosting.WebJobsHostBuilderExtensions.<>c__DisplayClass2_0.<ConfigureWebJobs>b__1(HostBuilderContext context, IServiceCollection services) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsHostBuilderExtensions.cs:line 37
   at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at Microsoft.Azure.WebJobs.Script.WebHost.DefaultScriptHostBuilder.BuildHost(Boolean skipHostStartup, Boolean skipHostConfigurationParsing) in C:\azure-webjobs-sdk-script\src\WebJobs.Script.WebHost\DefaultScriptHostBuilder.cs:line 59
   at Microsoft.Azure.WebJobs.Script.WebHost.WebJobsScriptHostService.BuildHost(Boolean skipHostStartup, Boolean skipHostJsonConfiguration) in C:\azure-webjobs-sdk-script\src\WebJobs.Script.WebHost\WebJobsScriptHostService.cs:line 267
   at Microsoft.Azure.WebJobs.Script.WebHost.WebJobsScriptHostService.StartHostAsync(CancellationToken cancellationToken, Int32 attemptCount, JobHostStartupMode startupMode) in C:\azure-webjobs-sdk-script\src\WebJobs.Script.WebHost\WebJobsScriptHostService.cs:line 134
cgillum commented 5 years ago

I think this question belongs in the WebJobs SDK repo. @fabiocav would you mind transferring it over and taking a look? The GitHub issue transfer feature isn't allowing me to do so myself (it's not visible to me).

coreConvention commented 5 years ago

@cgillum if you think thats where it needs to go great. However, I have only observed this behavior using durable functions. Everything seems to work as expected with the regular azure functions. shrugs

Anyhow, thanks for taking a look nonetheless!

coreConvention commented 5 years ago

I was able to get this sorted out. Turns out this fails when referencing any 2.2.0 versions of the Microsoft.Extensions.Configuration packages. Going back to 2.1.0 seems to fix the issue. Although even after that I had more issues with Microsoft.Extensions.Logging, because of a dependency on Microsoft.Extensions.DependecyInjection.Abstractions. In the end all of those related packages had to be downgraded to 2.1.0.

alan-g-chen commented 5 years ago

Adding on to say - it looks like this happens with any package in the Microsoft.Extensions namespace. I started encountering a similar issue when adding the Microsoft.Extensions.Caching.Memory 2.2.0 package.

codecat15 commented 4 years ago

@cgillum I am using version 3.1.0 of Microsoft.Extension and still getting the same issue, it seems that the configuration builder does have some crazy behavior with durable function. Given below is the code I am using, is there a workaround for this?

 private static AppSettings GetApplicationSettings()
        {
            var configBuilder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appSettings.json", optional: true, reloadOnChange: true).AddEnvironmentVariables().Build();

        var appSettings = new AppSettings();

        configBuilder.GetSection("AppSettings").Bind(appSettings);
        return appSettings;
    }