简体   繁体   中英

How do I access my configuration from within a static function in .Net Core 2.1?

I am creating an Azure web job in .Net Core 2.1 (via a "console" app in Visual Studio). In this project, I have a static function that reads messages from a queue. Within this function, I need to use connection strings (from my configuration) to write to a database. This is my setup:

Program.cs

class Program
{
    static void Main(string[] args)
    {
        var builder = new HostBuilder();
        builder.ConfigureWebJobs(b =>
        {
            b.AddAzureStorageCoreServices();
            b.AddAzureStorage();
        });
        builder.ConfigureAppConfiguration((hostContext, config) =>
        {
            var conf = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();
            config.AddConfiguration(conf);
            config.AddEnvironmentVariables();
        })
        builder.ConfigureLogging((context, b) =>
        {
            b.AddConsole();
        });
        var host = builder.Build();
        using (host)
        {
            host.Run();
        }
    }
}

Functions.cs

public class Functions
{
    public static void ProcessQueueMessage([QueueTrigger("myqueue")] string message, ILogger logger, IConfiguration configuration)
    {
        logger.LogInformation(message);
        logger.LogInformation(configuration.GetConnectionString("MyDatabase"));
    }
}

appsettings.json

{
  "ConnectionStrings": {
    "MyDatabase": "foo",
    "AzureWebJobsDashboard": "foo2",
    "AzureWebJobsStorage": "foo3"
  }
}

However, when I run this, I get the following error:

Error indexing method 'Functions.ProcessQueueMessage'

Cannot bind parameter 'configuration' to type IConfiguration. Make sure the parameter Type is supported by the binding. If you're using binding extensions (eg Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (eg builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

I am very new to .Net Core, especially the DI pattern. And I believe that is the issue. I also see many examples of how to implement and use the configuration from within the Main function, but not from within a static helper function like this. How do I properly implement my configuration from within my static function?

Consider changing the approach and not try to inject IConfiguration .

Create a class to hold your desired settings

public class MyOptions {
    public string MyDatabase { get; set; }
}

Refactor the setup to also use ConfigureServices and extract the desired configuration to populate the settings object and add it to the service collection

var builder = new HostBuilder();
builder
    .ConfigureWebJobs(b => {
        b.AddAzureStorageCoreServices();
        b.AddAzureStorage();
    })
    .ConfigureAppConfiguration(config => { //not using context so no need for it really
        config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();
        config.AddEnvironmentVariables();
    })
    //...ADDITION HERE
    .ConfigureServices((context, services) => {
        //Configuration should be available by now, so access what you need.
        var connectionString = context.Configuration.GetConnectionString("MyDatabase");
        //If null you have the option to fail early, otherwise carry on.
        var myOptions = new MyOptions {
            MyDatabase = connectionString,
        };
        services.AddSingleton(myOptions);
    }
    .ConfigureLogging((context, b) => {
        b.AddConsole();
    });

//...

That way at this point you should be able to add your object as a dependency to the function

public class Functions {
    public static void ProcessQueueMessage(
        [QueueTrigger("myqueue")] string message, 
        ILogger logger, 
        MyOptions options) {
        logger.LogInformation(message);
        logger.LogInformation(options.MyDatabase);
    }
}

I personally believe trying to access IConfiguration outside of startup to be more trouble than its worth and would even rank it with service locator anti-pattern and injecting IServiceProvider . Get what you need from it during setup, register that with service collection so it's available for injection where needed explicitly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM