c# - 你如何获得 IOptions来自服务的价值?
问题描述
我在开发时尝试做 TDD,但我很挣扎。我的第一个测试我可以成功获得在 services.AddAuthentication(...) 中设置的选项,但是我无法从添加到上一个调用中的 .AddCookie(..) 中获得选项。在调试期间,我确实看到为 CookieAuthenticationOptions 添加了一个 IPostConfigureOptions,我怀疑它以某种方式改变了默认选项值,但我不知道如何获取它。
要测试的代码:
public static void AddOpenIdConnect(this IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options => { options.MinimumSameSitePolicy = SameSiteMode.None; });
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(
CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.ExpireTimeSpan = TimeSpan.FromHours(2);
options.SlidingExpiration = true;
options.AccessDeniedPath = new PathString("/Error/403");
}
);
}
我的第一个测试确保设置了 AuthenticationOptions,并且它通过了:
[TestMethod]
public void AddOpenIdConnect_Should_AddAuthenticationOptions()
{
// arrange
var services = new ServiceCollection();
// act
services.AddOpenIdConnect();
// assert
var provider = services.BuildServiceProvider();
var authOptions = provider.GetRequiredService<IOptions<AuthenticationOptions>>();
authOptions.Value.DefaultScheme.Should().Be(CookieAuthenticationDefaults.AuthenticationScheme);
authOptions.Value.DefaultChallengeScheme.Should().Be(OpenIdConnectDefaults.AuthenticationScheme);
}
此方法失败,因为 AccessDeniedPath 返回默认设置,而不是正在测试的代码设置的设置(您可以看到我注释掉了对 ExpireTimeSpan 的检查,因为它也失败了。)
[TestMethod]
public void AddOpenIdConnect_Should_AddCookieAuthenticationOptions()
{
// arrange
var services = new ServiceCollection();
// act
services.AddOpenIdConnect();
// assert
var provider = services.BuildServiceProvider();
var authCookieOptions = provider.GetRequiredService<IOptions<CookieAuthenticationOptions>>();
//authCookieOptions.Value.ExpireTimeSpan.Should().Be(TimeSpan.FromHours(2));
authCookieOptions.Value.SlidingExpiration.Should().BeTrue();
authCookieOptions.Value.AccessDeniedPath.Should().Be("/Error/403");
}
任何帮助将不胜感激,因为在此之后我仍然需要添加“.AddOpenIdConnect(options =>”。
谢谢!
解决方案
扩展程序的源代码AddCookie
显示,在添加时使用身份验证方案配置命名选项CookieAuthenticationOptions
public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder,
string authenticationScheme, string displayName, Action<CookieAuthenticationOptions> configureOptions)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
builder.Services.AddOptions<CookieAuthenticationOptions>(authenticationScheme).Validate(o => o.Cookie.Expiration == null, "Cookie.Expiration is ignored, use ExpireTimeSpan instead.");
return builder.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
}
注意
builder.Services.AddOptions<CookieAuthenticationOptions>(authenticationScheme) //<-- Named option
因此,需要使用注册选项时使用的相同方案才能访问 name 选项
这可以使用IOptionsSnapshot<TOptions>.Get(String)
方法来完成
//...omitted for brevity
// Assert
var provider = services.BuildServiceProvider();
IOptionsSnapshot<CookieAuthenticationOptions> namedOptionsAccessor =
provider.GetRequiredService<IOptionsSnapshot<CookieAuthenticationOptions>>();
CookieAuthenticationOptions options =
namedOptionsAccessor.Get(CookieAuthenticationDefaults.AuthenticationScheme);
options.ExpireTimeSpan.Should().Be(TimeSpan.FromHours(2));
options.SlidingExpiration.Should().BeTrue();
options.AccessDeniedPath.Should().Be("/Error/403");
推荐阅读
- mysql - 更新 mysql nodejs
- python - 为什么每一层都采用初始输入数组形状而不是前一层的输出
- swift - 迅速。UISegmentedControl 有两条不同的线
- java - 包 androidx.appcompat.widget 不存在 Android Studio
- vb.net - 如何过滤通用对象列表
- python - 如何删除从文件中读取的字符串中的编码“b”?
- animation - Pygame是在不暂停程序的情况下减慢某个动画的帧速率的最佳方法?
- wpf - 如何修复 WPF MVVM 中的绑定 TextBlock?
- android - 有没有办法从我的 expo 应用程序 (react native 解决方案) 在“添加页面”上打开 instagram 应用程序?
- javascript - 如何遍历本地存储中的对象集合