Получить корневой каталог приложения-функции Azure v2

Я создаю приложение-функцию Azure (v2). Задачи конфигурации, необходимые для всех функций, выполняются в классе Setup, который структурирован следующим образом:

[assembly: WebJobsStartup(typeof(Startup))]

internal class Startup : IWebJobsStartup
{
  public void Configure(IWebJobsBuilder builder)
  {
    Configuration = new ConfigurationBuilder()
                      .SetBasePath(<functionAppDirectory>)
                      .AddJsonFile("local.settings.json")
                      .Build();
    builder.AddDependencyInjection(ConfigureServices);  
  }

  public IConfiguration Configuration { get; set; }

  private void ConfigureServices(IServiceCollection services)
  {
    var connection = Configuration.GetConnectionString("<myconnection-string>");
    ...
  }
}

В ConfigureServices я хочу прочитать строку подключения из файла конфигурации. Для этого была указана базовая папка приложения функции с помощью SetBasePath. Но я не нашел способа получить доступ к этому пути. Согласно https://github.com/Azure/azure-functions-host/wiki/Retrieving-information-about-the-currently-running-function, ExecutionContext может быть введен в функцию, которая содержит путь. Но как мне получить доступ к ExecutionContext в моем классе Startup?

Ответ 1

TL; DR: просто используйте Environment.GetEnvironmentVariable.

Подход ConfigurationBuilder обнаруживается во многих постах блога и работал до тех пор, пока мы не начали делать DI. Но здесь нет параметра контекста, поэтому ConfigurationBuilder сразу начинает вызывать некоторое напряжение.

Я думаю, что люди пошли в этом направлении, потому что в Azure Functions 2 мы переключились на конфигурацию ядра ASP.NET, из-за чего ConfigurationManager перестал работать. Конфигурация Builder была разумным местом для посадки. Он был схож с MVC и работал до появления DI.

Но теперь, когда мы выполняем DI, стало ясно, что Environment.GetEnvironmentVariable, возможно, был лучшим выбором для этой платформы... Там меньше накладных расходов кода, и он четко отображается в модели конфигурации функций Azure: в dev, это подбирает элементы в массиве local.settings.json> Values, а в производственном процессе он выбирает переменные вашей среды, и он просто работает.

Это отличается от того, что мы делаем в MVC. Однако до тех пор, пока эти платформы не станут ближе к паритету, мы должны делать то, что имеет смысл в функциях, а не пытаться навязывать решения из MVC.

Итак:

[assembly: WebJobsStartup(typeof(StartUp))]
namespace Keystone.AzureFunctions
{

    public class StartUp : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {           
            var connectionString = Environment.GetEnvironmentVariable("KeystoneDB");

            // Configure EF
            builder.Services.AddDbContext<KeystoneDB>(options => options.UseSqlServer(connectionString));
        }
    }
}

И ваш local.settings.json может выглядеть так:

{
    "IsEncrypted": false,
    "Values": {
        "KeystoneDB": "[CONNECTION STRING HERE]"
        "FUNCTIONS_WORKER_RUNTIME": "dotnet"
    }
}

Вы также можете использовать Key Vault с Environment. Это прекрасно работает.

Ответ 2

Единственный обходной путь, который я нашел для компоновщика конфигурации в методе Startup(), - это использовать жестко закодированный путь "/home/site/wwwroot/"

var config = new ConfigurationBuilder()
                .SetBasePath("/home/site/wwwroot/")
                .AddJsonFile("config.json", optional: false)
                .Build();

System.Environment.CurrentDirectory не работает в Azure. Хотя это работает локально. Но в Azure выдает ошибку: файл конфигурации 'config.json' не найден и не является обязательным. Физический путь - "/config.json". И функция не запускается.

Ответ 4

Приветствие,
Я нашел решение, которое работает в автозагрузке:

var fileInfo = new FileInfo(Assembly.GetExecutingAssembly().Location);
string path = fileInfo.Directory.Parent.FullName;
var configuration = new ConfigurationBuilder()
    .SetBasePath(Environment.CurrentDirectory)
    .SetBasePath(path)
    .AddJsonFile("appsettings.json", false)
    .Build();

Ответ 5

Вы можете использовать этот кусок кода в вашем файле запуска. Я только что проверил его сегодня для своего проекта, и он работает как на облачном, так и на локальном уровне.

var executioncontextoptions = builder.Services.BuildServiceProvider()
    .GetService<IOptions<ExecutionContextOptions>>().Value;
var currentDirectory = executioncontextoptions.AppDirectory;

Ответ 6

Попробуйте использовать Environment.CurrentDirectory