适用于ServiceBusTrigger的appsettings.json中代表的Azure函数local.settings.json

时间:2019-01-02 14:43:00

标签: azure azure-functions azureservicebus

我目前使用ServiceBusTrigger绑定具有azure功能

 [ServiceBusTrigger("%TopicName%", "%SubscripionName%", Connection = "MyConnection")]
         string  catclogueEventMsgs, ILogger log, ExecutionContext context)

使用此local.settings.json文件

   "Values": {
             …
    "MyConnection": "Endpoint=sb://testxxxxxxxxxxxxxxxxxx
    "SubscriptionName": "testsubscriptionName"
    "TopicName": "testtopicName",
  }

我该如何在appsettings.json文件中表示它。会像下面吗?

   "Values": {
    "MyConnection": "Endpoint=sb://testxxxxxxxxxxxxxxxxxx
    "SubscriptionName": "testsubscriptionName"
    "TopicName": "testtopicName",
  }

我可以像下面这样使用“ MySubs”对象代替我的“ Values”对象吗?

   "MySubs": {
    "MyConnection": "Endpoint=sb://testxxxxxxxxxxxxxxxxxx
    "SubscriptionName": "testsubscriptionName"
    "TopicName": "testtopicName",
  }

如果可以使用上述设置,我该如何在ServiceBusTrigger绑定中表示它?我会改成这个吗?

 [ServiceBusTrigger("%MySubs.TopicName%", "%MySubs.SubscripionName%", Connection = "MySubs.MyConnection")]
         string  catclogueEventMsgs, ILogger log, ExecutionContext context)

4 个答案:

答案 0 :(得分:2)

恐怕是不可能的。根据设计,本地Azure Function在Values文件中读取local.settings.json来检索与绑定相关的设置。

检查local.settings.jsonValues的描述。

  

在本地运行时使用的应用程序设置和连接字符串的集合。这些值与Azure中的功能应用程序中的应用程序设置相对应,例如AzureWebJobsStorage和AzureWebJobsDashboard。

     

许多触发器和绑定具有引用连接字符串应用程序设置的属性,例如Blob存储触发器的Connection。对于此类属性,您需要在Values数组中定义的应用程序设置。

对于生产环境(即在Azure网站上),我们只能依靠Application settings来检索与绑定相关的设置。

答案 1 :(得分:1)

您确实可以按以下方式读取Values数组之外的设置:

WeatherApiConfig.cs

public class WeatherApiConfig
{
    public string WeatherApiUrl { get; set; }
    public string WeatherApiKey { get; set; }
}
  

Azure Functions V2的新增功能we have an appropriate way to handle DI,如下所示:

Startup.cs

[assembly: FunctionsStartup(typeof(BlazingDemo.Api.Startup))]

namespace BlazingDemo.Api
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables()
                .Build();

            var apiConfig = new WeatherApiConfig();
            config.GetSection("WeatherApiConfig").Bind(apiConfig);

            builder.Services.AddSingleton(apiConfig);
            builder.Services.AddHttpClient();
        }
    }
}

Local.settings.json

{  
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet"
  },
  "WeatherApiConfig": {
    "WeatherApiUrl": "http://api.openweathermap.org/data/2.5/weather",
    "WeatherApiKey": "**removed**"
  }
}
  

注意:对我来说,关键是在.SetBasePath(Directory.GetCurrentDirectory())中添加Startup.cs,因为没有它找不到文件。

在生产环境中,我使用功能应用程序的Application Settings部分来配置这两个属性,如下所示:

Application Settings in Azure

答案 2 :(得分:0)

看起来 Jason 和 Oneil/Liam 的混合体是正确的。

  • 据我所知,在函数的名称/声明/定义中,它必须来自开发时的local.settings.json,并像“%TheQueueName%”一样引用,然后在Function中输入配置 -> Azure 应用程序设置。

  • 在实际函数本身中,您可以通过 Startup.cs 利用 json 文件注入,然后将值包含在函数本身中。

这值得一个完全独立的博客文章(并且有类似的,但没有提到的那么复杂的设置,但这是我在一年多后所做的和想出来的,并且效果非常好。

文件设置:

  1. 我在 Functions 项目中有一个 Config 文件夹,用于存储 xyz.settings.json 文件。此处的文件在 .csproj 文件中设置为“内容”,然后设置为“构建”和“发布”。
  2. 在 Config 文件夹中,我还有一个 secrets.json 文件,用于存储我不想发布的所有机密。 这设置为仅构建,不发布!对于我想要保密的值,每个 xyz.settings.json 文件都有一个“--SECRET--”值。
  3. local.settings.json 具有用于开发的“值”的值对。这也仅用于构建。然后将这些值添加到 Azure 中已发布应用程序的函数门户。这些值仅用于函数名称/声明/定义。
  4. 我创建了一个与 xyz.settings.json 文件中的值相对应的类。这使您可以通过注入访问值。此外,在功能应用设置中,您可以在输入秘密值时通过 XyzSettings:Value 引用这些值。

配置设置:Startup.cs

(即使它说 /home/site/wwwroot - 文件基于项目的根目录,发布时将是根目录)

public override void Configure(IFunctionsHostBuilder builder)
  {
    var currentDirectory = "/home/site/wwwroot";
    var config = new ConfigurationBuilder()
        .SetBasePath(currentDirectory)
        .AddJsonFile("local.settings.json", optional: false, reloadOnChange: true)
        .AddJsonFile("Config/xyz.settings.json", optional: false, reloadOnChange: true)
        .AddJsonFile("Config/xyz.settings.dev.json", optional: true, reloadOnChange: true)
        .AddJsonFile("Config/secret.settings.json", optional: true, reloadOnChange: true)
        .AddEnvironmentVariables()
        .Build();
    builder.Services.Configure<XyzSettings>(config.GetSection("XyzSettings"));

它有什么作用以及它是如何工作的:

  • 应用程序设置以非常特定的顺序应用,json 文件按照它们的添加顺序应用。如果存在重复设置,现有文件将被覆盖。
  • 我先有 local.settings。然后是通用json文件(xyz.settings.json),然后是环境特定变体(zyx.settings.dev.json),然后是secrets.json
  • 环境特定变量放在最后(这些是您在机器上指定的 - 或等效的功能应用程序设置)
  • 这种方法可以让您拥有一组非常好的和稳定的设置。如果您的项目包含许多不同的集成、API 等,这将特别有用。它们都可以是不同的文件。
  • 注意最后两个 json 文件是如何标记为可选的。它们必须是,因为它们在发布时不包括在内。任何需要但未包含的 json 文件都将导致函数失败。

说到秘密:

  • 本地机密可以存储在 secrets.json 中,只要它们未设置为发布即可。

  • 在 Azure 中,建议将值存储在可访问 Azure Key Vault 的 Function App Settings 中。

  • 它的配置方式非常棒。您在 Function App Settings 中所做的就是将变量命名为它在设置中的名称,例如 XyzSettings:SettingName,然后引用 Key Vault 中的位置,如下所示:

    @Microsoft.KeyVault(SecretUri=https://yourvalutname.vault.azure.net/secrets/secret-name/auto-generated-keyvaultguid)

函数文件: (以队列触发器为例,但操作方式相同)

namespace Xyz.Functions
{
   public class Azure_Queue_Add_Xyz
   {
        private readonly XyzSettings _xyzSettings = null;

        public Azure_Queue_Add_Xyz(IOptions<AzureSettings> azure_settings)
        {
            _azureSettings = azure_settings.Value;
        }

        [FunctionName("Azure_Queue_Add_Xyz")]
      public void Run(
            [HttpTrigger(AuthorizationLevel.Function, "post",
            Route = "HttpTrigger/Azure_Queue_Add_Xyz")] xyzConfig input,
            [Queue("%TheQueueName%"), StorageAccount("StorageAccount")] ICollector<string> msgOutput,
            ILogger logger,
            ExecutionContext context)
      {
            logger.LogError("{0} is processing a request", context.FunctionName);
            logger.LogError("{0} - Queue: {1}", context.FunctionName, _xyzSettings.TheQueueName);
            logger.LogError("{0} - CloudQueueMessage: {1}", context.FunctionName, JsonConvert.SerializeObject(input));

            msgOutput.Add(JsonConvert.SerializeObject(input));
      }
   }
}

答案 3 :(得分:0)

这是如何为 .NET 5 做这件事,例如一些覆盖秘密的例子:

Kotobee 设置:

public class KotobeeSettings
{
    public string BaseUrl { get; set; }

    public string SerialNumber { get; set; }
}

Program.cs:

public class Program
{
    public static void Main()
    {
        var host = new HostBuilder()
            .ConfigureFunctionsWorkerDefaults()
            .ConfigureAppConfiguration((hostContext, builder) =>
            {
                builder.AddJsonFile("local.settings.json");
                //This will override any values added to local.settings.json if you wish to check in this file - Recommended approach for keeping secrets in dev is this though:
                //https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-5.0&tabs=windows#register-the-user-secrets-configuration-source
                //builder.AddJsonFile("secrets.settings.json");

                if (hostContext.HostingEnvironment.IsDevelopment())
                {
                    builder.AddUserSecrets<Program>();
                }

            })
            .ConfigureServices((hostContext, services) =>
            {
                var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings:DefaultConnection");
                services.AddDbContext<ApplicationDbContext>(options =>
                        options.UseSqlServer(
                        connectionString,
                        sqlServerOptions => sqlServerOptions.CommandTimeout(600)));

                services.AddHttpClient();

                var configuration = hostContext.Configuration;

                var settings = new KotobeeSettings();
                configuration.Bind("KotobeeSettings", settings);
                services.AddSingleton(settings);

                services.AddTransient<KotobeeClient>();
                services.AddTransient<OrderRowService>();
            })
            .Build();
        CreateDbAndApplyMigrations(host);

        host.Run();
    }

    private static void CreateDbAndApplyMigrations(IHost host)
    {
        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;

            var context = services.GetRequiredService<ApplicationDbContext>();
            context.Database.Migrate();
        }
    }

示例 local.settings.json:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=Project.Ebook;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "KotobeeSettings": {
    "BaseUrl": "BaseURL",
    "SerialNumber": "--SECRET--"
  }
}

例如secrets.settings.json 和secrets.json:

{
  "KotobeeSettings": {
    "SerialNumber": "123"
  }
}

像这样注入的设置:

public class TimerTrigger
{
    private readonly OrderRowService _orderRowService;
    private readonly KotobeeSettings _settings;

    public TimerTrigger(OrderRowService orderRowService, KotobeeSettings settings)
    {
        _orderRowService = orderRowService;
        _settings = settings;
    }

    [Function("TimerTrigger")]
    public async Task RunAsync([TimerTrigger("0 */1 * * * *")] MyInfo myTimer, FunctionContext context)
    {
        var baseUrl = _settings.BaseUrl;

        var logger = context.GetLogger("TimerTrigger");
        logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
        logger.LogInformation($"Next timer schedule at: {myTimer.ScheduleStatus?.Next}");
    }
}

public class MyInfo
{
    public MyScheduleStatus ScheduleStatus { get; set; }

    public bool IsPastDue { get; set; }
}

public class MyScheduleStatus
{
    public DateTime Last { get; set; }

    public DateTime Next { get; set; }

    public DateTime LastUpdated { get; set; }
}