【问题标题】:Azure WebJobs SDK 3, trying to add a BlobTrigger and related connection stringAzure WebJobs SDK 3,尝试添加 BlobTrigger 和相关连接字符串
【发布时间】:2018-11-06 18:01:30
【问题描述】:

旧的做事方式是这样的:

        var jobConfig = new JobHostConfiguration(cfg.DocumentDatabase.BlobStorageServer)
        {
            NameResolver = new Support.BlobNameResolver(_env)
        };
        jobConfig.Queues.MaxPollingInterval = TimeSpan.FromSeconds(_pollSeconds);

        _wjHost = new JobHost(jobConfig);

我正在尝试将其转换为 3.0 中的新方式,这就是我已经走了多远:

        _wjHost = new HostBuilder().ConfigureWebJobs(b =>
        {
            b.AddAzureStorage(x =>
            {
                x.MaxPollingInterval = TimeSpan.FromSeconds(_pollSeconds);
            });
        }).ConfigureServices(s =>
        {
            s.AddSingleton<INameResolver, Support.BlobNameResolver>(_ => new Support.BlobNameResolver(_env));
            s.Configure<QueuesOptions>(o =>
            {
                o.MaxPollingInterval = TimeSpan.FromSeconds(_pollSeconds);
            });
        }).Build();

首先,我不知道哪个MaxPollingInterval 适合使用...所以我两个都设置了。我想我不应该使用AddBlobStorage中的那个

其次,更重要的是,我在哪里指定 blob 存储连接字符串?在上面的例子中,它是存储在cfg.DocumentDatabase.BlobStorageServer中的设置

谢谢

【问题讨论】:

    标签: c# azure azure-webjobs azure-webjobssdk


    【解决方案1】:

    官方样品可在WebJob Github获取

    在您的函数中,您可以传递在 appsettings.json

    例如:

    public void ProcessBlob([BlobTrigger("blobPath", Connection = "AzureWebJobsBlobConnection")] string blob)
    

    “AzureWebJobsBlobConnection”在appsettings.json 中配置如下: { "Logging": { ... }, "AzureWebJobsBlobConnection": "...", }

    并且不要忘记在program.cs中添加配置:

    var builder = new HostBuilder()
                .ConfigureAppConfiguration((builderContext, cb) =>
                {
                    IHostingEnvironment env = builderContext.HostingEnvironment;
    
                    cb.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
                })
                .ConfigureWebJobs(b =>
                {
                    b.AddAzureStorage(o => 
                    {
                        o.MaxDequeueCount = 1;
                    })
                    .AddServiceBus(c =>
                    {
                        c.MessageHandlerOptions.MaxConcurrentCalls = 1;
                    });
                })
                .ConfigureLogging((webHostBuilder, loggingBuilder) =>
                {
                    loggingBuilder.AddConsole();
                    loggingBuilder.AddDebug();
                })
                .ConfigureServices((hb, sc) =>
                {
                    string connectionString = hb.Configuration.GetConnectionString("DefaultConnection");
    
                    sc.AddScoped<Functions, Functions>();
                    ...
                });
    
            builder.RunConsoleAsync().GetAwaiter().GetResult();
    

    【讨论】:

    • 我在该示例中看不到您设置连接字符串的任何地方。您能否说明这一点?这就是这个问题要问的。
    • @Andy 我加了一个例子,使用和官方 GitHub 一样的逻辑
    • 在代码示例中,connectionString 未使用。这肯定不正确?
    • @PeterTaylor 这只是一个如何获取连接字符串的示例,确保在我的代码中我注册了dbcontext 并使用connectionString
    【解决方案2】:

    所以,在盯着 webjob SDK 的源代码之后,我发现了一个杂牌。嗯,我认为这是一个kludge。它工作正常,我现在可以使用新的 3.0 SDK。

    我在这里发布这个,主要是因为我担心没有其他方法可以使用我自己的配置文件来做到这一点。

    如果这是错误的,请告诉我,我会删除这个答案。

    所以我的代码现在看起来像这样:

        _wjHost = new HostBuilder().ConfigureWebJobs(b =>
        {
            b.AddAzureStorage(x =>
            {
                x.MaxPollingInterval = TimeSpan.FromSeconds(_pollSeconds);
            });
        }).ConfigureServices(s =>
        {
            s.AddSingleton(new StorageAccountProvider(new BlobStorageConfiguration(cfg.DocumentDatabase.BlobStorageServer)));
            s.AddSingleton<INameResolver, Support.BlobNameResolver>(_ => new Support.BlobNameResolver(_env));
            s.Configure<QueuesOptions>(o =>
            {
                o.MaxPollingInterval = TimeSpan.FromSeconds(_pollSeconds);
            });
        }).Build();
    

    我添加的行是s.AddSingleton(new StorageAccountProvider(new BlobStorageConfiguration(cfg.DocumentDatabase.BlobStorageServer)));

    webjobs SDK 专门寻找名为 Storage 的密钥。所以我必须实现IConfiguration 并将其合并:

    private sealed class BlobStorageConfiguration : IConfiguration
    {
        private readonly string _bsConnString;
        public BlobStorageConfiguration(string connString)
        {
            _bsConnString = connString;
        }
    
        public string this[string key]
        {
            get => key == "Storage" ? _bsConnString : null;
            set { }
        }
    
        public IEnumerable<IConfigurationSection> GetChildren() => null;
        public IChangeToken GetReloadToken() => null;
        public IConfigurationSection GetSection(string key) => null;
    }
    

    现在触发器触发得很好。不漂亮。但是关于新的 IHost 方法的文档为零。

    【讨论】:

    • 感谢您的分享。您可以将其标记为答案,以便对其他人有所帮助:)
    【解决方案3】:

    在 WebSDK 3 中,作业是通过 appsettings.json 文件配置的,与 ASP.NET Core 的配置方式相同。

    你可以看到一个例子on the official Github repo,但我也会在下面添加一个更完整的例子。

    appsettings.development.json 中,通过ConnectionStrings["AzureWebJobsStorage"] 属性将其配置为使用本地存储:

    {
      "ConnectionStrings": {
        "AzureWebJobsDashboard": "UseDevelopmentStorage=true",
        "AzureWebJobsStorage": "UseDevelopmentStorage=true"
      }
    }
    

    appsettings.json 中,为 prod 配置它:

    {
      "ConnectionStrings": {
        "AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=key",
        "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=key"
      }
    }
    

    我的完整 Program.cs 看起来像这样(带有 cmets):

    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = new HostBuilder();
    
            // allows us to read the configuration file from current directory
            // (remember to copy those files to the OutputDirectory in VS)
            builder.UseContentRoot(Directory.GetCurrentDirectory());
    
            // configure things like batch size, service bus, etc..
            builder.ConfigureWebJobs(b =>
            {
                b
                .AddAzureStorageCoreServices()
                .AddAzureStorage(options =>
                {
                    options.BatchSize = 1;
                    options.MaxDequeueCount = 1;
                })
                ;
            });
    
            // this step allows the env variable to be read BEFORE the rest of the configuration
            // => this is useful to configure the hosting environment in debug, by setting the 
            // ENVIRONMENT variable in VS
            builder.ConfigureHostConfiguration(config =>
            {
                config.AddEnvironmentVariables();
            });
    
            // reads the configuration from json file
            builder.ConfigureAppConfiguration((context, config) =>
            {
                var env = context.HostingEnvironment;
    
                // Adding command line as a configuration source
                config
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
    
                config.AddEnvironmentVariables();
                if (args != null)
                    config.AddCommandLine(args);
            });
    
            // configure logging (you can use the config here, via context.Configuration)
            builder.ConfigureLogging((context, loggingBuilder) =>
            {
                loggingBuilder.AddConfiguration(context.Configuration.GetSection("Logging"));
                loggingBuilder.AddConsole();
    
                // If this key exists in any config, use it to enable App Insights
                var appInsightsKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
                if (!string.IsNullOrEmpty(appInsightsKey))
                {
                    loggingBuilder.AddApplicationInsights(o => o.InstrumentationKey = appInsightsKey);
                }
            });
    
            // inject dependencies via DI
            builder.ConfigureServices((context, services) =>
            {
                services.AddSingleton<INameResolver>(new QueueNameResolver("test"));
    
                services.AddDbContextPool<DbContext>(options =>
                    options.UseSqlServer(context.Configuration.GetConnectionString("DbContext"))
                );
            });
    
            // finalize host config
            builder.UseConsoleLifetime();
    
            var host = builder.Build();
            using (host)
            {
                await host.RunAsync();
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      以防万一有人遇到我在使用 QueueTrigger 时解析队列名称时遇到的相同情况:

      您必须使用“Microsoft.Extensions.DependencyInjection”包才能使以下代码正常工作。

      static void Main(string[] args)
          {
              var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
              Console.WriteLine($"Current Environment : {(string.IsNullOrEmpty(environment) ? "Development" : environment)}");
      
              var config = new ConfigurationBuilder()
                  .SetBasePath(Directory.GetCurrentDirectory())
                  .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                  .AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true)
                  .AddEnvironmentVariables()
                  .Build();
      
              var builder = new HostBuilder();
              builder.UseEnvironment("Development");
              builder.ConfigureLogging((context, b) =>
              {
                  b.AddConsole();
              });
      
              builder.ConfigureWebJobs(b =>
              {
      
                  b.AddAzureStorageCoreServices();
                  b.AddAzureStorage();
                  // b.AddTimers();
      
                  b.AddServiceBus(c =>
                  {
                      c.ConnectionString = "[Your Connection String]";
                  });
              }).ConfigureServices((context, services)=>
              {
                  services.AddSingleton<INameResolver>(new QueueNameResolver(config));
              });
      
              var host = builder.Build();
      
      
              using (host)
              {
                  host.Run();
              }
          }
      
      public class QueueNameResolver : INameResolver
      {
          private readonly IConfiguration _configuration;
          public QueueNameResolver(IConfiguration configuration)
          {
              _configuration = configuration;
          }
          public string Resolve(string name)
          {
              return _configuration[$"AppSettings:{name}"];
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-07
        • 1970-01-01
        • 2020-05-04
        相关资源
        最近更新 更多