我正在尝试为 ASP.NET Core 2.0 应用/网站配置我的服务。
我希望在此方法中引用我的 appsettings.json
文件中的一些键/值。
我不确定我要做的事情是否可行:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddJsonFormatters()
.AddCors();
var applicationSettings = Configuration.GetSection("Settings").Get<ApplicationSettings>();
services.AddSingleton(applicationSettings);
// ** THIS IS WHAT I ORIGINALLY HAD, BUT IT'S ONLY SETTING
// THE VALUE IN DI/IOC.
//services.Configure<ApplicationSettings>(options => Configuration.GetSection("Settings")
// .Bind(options));
var foo = new Foo(applicationSettings.SomeSetting);
services.AddSingleton(foo);
}
看看我如何手动添加单例,然后从应用设置实例引用一个值?
对比
刚刚配置...
那么,这两种方式都可以吗?或者是否有特定原因?
记住 -> 我需要将我的设置注入(inject) Controller 等......
最佳答案
从技术上讲,您可以选择其中任何一种。在这两种情况下,您都已通过依赖项注入(inject)注册并可用配置,因此一切都可以依赖它并获取配置实例。
您还使用集中设置的Configuration
那里,所以你可以从那里的配置堆栈中获得所有好处,例如多个提供程序或特定于环境的覆盖。
但是,这种青睐肯定转移到了 IOptions
上。使用自定义配置的方式。它是“最先进的技术”,在 ASP.NET Core 中用于几乎所有的事情。它还允许您切换到可以在运行时更新的选项。这非常强大,最终可能会变得有用(不一定适用于单例的特定情况,但可能适用于其他情况)。
设置起来也非常容易,实际上比您尝试的要短:
services.Configure<ApplicationSettings>(Configuration.GetSection("Settings"));
services.AddSingleton<Foo>();
请注意,即使对于单例,您也不应该显式创建它的新实例,而是让 DI 处理它。如果您的类具有正确的构造函数,则无论如何都会自动注入(inject)依赖项:
public class Foo
{
private readonly ApplicationSettings _settings;
public Foo (IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
}
当然,Foo
这里还可以有更多的依赖。由于它将由 DI 构建,因此您可以在构造函数中添加更多依赖项,而无需更新一些 new
打电话到某个地方。
如果您需要使用取决于您的配置的设置来配置某些服务,您仍然不应该直接在那里绑定(bind)您的配置。所有配置都是基于DI的,所以你只需要注入(inject)正确的东西;一个IConfigureOptions<T>
。这基本上就是提供IOptions<T>
的东西稍后再到服务。在您的 JWT 案例中,这可能如下所示:
// instead of passing an option configuration delegate here…
services.AddAuthentication().AddJwtBearer();
// … we register a IConfigureOptions<JwtBearerOptions> instead
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>();
// … ConfigureJwtBearerOptions could look like this:
class ConfigureJwtBearerOptions : IConfigureOptions<JwtBearerOptions>
{
private readonly ApplicationSettings _settings;
public ConfigureJwtBearerOptions(IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
public void Configure(JwtBearerOptions options)
{
// configure JwtBearerOptions here, and use your ApplicationSettings
options.MetadataAddress = _settings.JwtMetadataAddress;
}
}
与仅将委托(delegate)传递给 AddJwtBearer()
相比,这可能看起来不必要的冗长。但请注意,这正是当您传递该委托(delegate)时在后台发生的情况:An IConfigureOptions<JwtBearerOptions>
将创建调用 Configure()
中的委托(delegate)的对象称呼。所以这实际上是一样的。
请注意,对于身份验证方案,您实际上可能会设置 IConfigureNamedOptions<T>
相反,这几乎是相同的事情,只是它可以根据名称配置选项。对于身份验证方案,即方案名称,因此基本上您可以在 Configure()
中检查方案名称。然后决定如何配置您的选项。
至于创建单例实例,尤其是昂贵的实例,我认为 ConfigureServices
这种事放错地方了。 ConfigureServices
在应用程序启动阶段的早期调用,此时整个 DI 基础设施尚不存在。因此,在创建实例时您不能依赖任何东西。我还认为,创建对象仍然不是您的工作,但您应该 DI 处理它的创建,因此也可以控制其生命周期。
如果您绝对需要控制实例的创建时间,我建议您为此使用生命周期事件:基本上,在应用程序正确设置之后但在第一个请求到来之前,您请求服务实例并对其进行初始化。这样,您仍然可以让它完全依赖于 DI,并且它不会在第一个请求时延迟创建。
您可以在 Configure
中注册生命周期处理程序方法:
public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
applicationLifetime.ApplicationStarted.Register(() =>
{
// application has started, request the singleton here to trigger DI to
// create the instance
app.ApplicationServices.GetService<ExpensiveSingleton>();
});
// …
}
}
关于c# - 我应该如何在启动时在 ConfigurationServices ASP.NET Core 2.0 中使用 appsettings.json 配置键/值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46117430/