Azure WebJobs SDK 3,尝试添加 BlobTrigger 和相关的连接字符串
Azure WebJobs SDK 3, trying to add a BlobTrigger and related connection string
旧的处理方式是这样的:
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
中的设置
谢谢
因此,在查看了 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 方法的文档为零。
获取官方样本
在您的函数中,您可以传递在
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();
在 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
中为产品配置它:
{
"ConnectionStrings": {
"AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=key",
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=key"
}
}
我的完整 Program.cs
看起来像这样(有评论):
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();
}
}
}
以防万一有人遇到与我在使用 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}"];
}
}
旧的处理方式是这样的:
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
谢谢
因此,在查看了 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 方法的文档为零。
在您的函数中,您可以传递在
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();
在 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
中为产品配置它:
{
"ConnectionStrings": {
"AzureWebJobsDashboard": "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=key",
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=name;AccountKey=key"
}
}
我的完整 Program.cs
看起来像这样(有评论):
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();
}
}
}
以防万一有人遇到与我在使用 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}"];
}
}