【发布时间】:2020-08-08 18:30:26
【问题描述】:
Tl;dr:我想要一个选项类,它对其成员使用不可为空的类型,没有默认值。
C# 8.0 引入Nullable Reference Types.
我发现在 ASP.Net Options Pattern 中使用可为空的引用类型相当困难、不完整,或者我遗漏了一些东西。我遇到了stack over flow post 中描述的相同问题。
- 我们不想让 Name 可以为空,因为我们需要在任何地方进行传统的空检查(这违背了不可为空引用类型的目的)
- 我们无法创建构造函数来强制使用不可为空的名称值创建 MyOptions 类,因为 Configure 方法为我们构造选项实例
- 我们不能使用 null-forgiving 运算符技巧 (public string name { get; set; } = null!;),因为这样我们就不能确保 Name 属性已设置并且我们最终会在不期望出现这种情况的 Name 属性(在服务内部)
我想要一个对其成员使用不可为空类型且没有默认值的选项类。 该帖子中的答案最终还是使用可空类型(我试图避免)或默认值(我也试图避免)。
关于 options validation 的 cmets 提出了很好的观点并且看起来很有希望,但事实证明 Validate 方法仍然需要一个选项对象来验证,如果您已经必须将选项对象传递给它。
public ValidateOptionsResult Validate(string name, MyOptions options)
// Pointless if MyOptions options is being passed in here
这是没有意义的,因为我已经确定强制使用所有不可为空的成员且没有默认值的选项类的唯一方法是拥有一个构造函数。以下面的代码示例为例。
namespace SenderServer.Options
{
using System;
using Microsoft.Extensions.Configuration;
/// <summary>
/// Configuration options for json web tokens.
/// </summary>
public class JwtOptions
{
/// <summary>
/// The secret used for signing the tokens.
/// </summary>
public String Secret { get; }
/// <summary>
/// The length of time in minutes tokens should last for.
/// </summary>
public Int32 TokenExpirationInMinutes { get; }
/// <summary>
/// Configuration options for json web tokens.
/// </summary>
/// <param name="secret"> The secret used for signing the tokens.</param>
/// <param name="tokenExpirationInMinutes">The length of time in minutes tokens should last for.</param>
public JwtOptions(String secret, Int32 tokenExpirationInMinutes)
{
Secret = secret;
TokenExpirationInMinutes = tokenExpirationInMinutes;
}
/// <summary>
/// Create a JwtOptions instance from a configuration section.
/// </summary>
/// <param name="jwtConfiguration">The configuration section.</param>
/// <returns>A validated JwtOptions instance.</returns>
public static JwtOptions FromConfiguration(IConfiguration jwtConfiguration)
{
// Validate the secret
String? secret = jwtConfiguration[nameof(Secret)];
if (secret == null)
{
throw new ArgumentNullException(nameof(Secret));
}
// Validate the expiration length
if (!Int32.TryParse(jwtConfiguration[nameof(TokenExpirationInMinutes)], out Int32 tokenExpirationInMinutes))
{
throw new ArgumentNullException(nameof(TokenExpirationInMinutes));
}
if (tokenExpirationInMinutes < 0)
{
throw new ArgumentOutOfRangeException(nameof(TokenExpirationInMinutes));
}
return new JwtOptions(secret, tokenExpirationInMinutes);
}
}
}
所以如果我需要一个带有类参数的构造函数,那么我可以自己实例化它:
// Configure the JWT options
IConfiguration jwtConfiguration = Configuration.GetSection("Authentication:JwtOptions");
JwtOptions jwtOptions = JwtOptions.FromConfiguration(jwtConfiguration); // This performs validation as well
但是我应该把jwtOptions 放在哪里呢? services.Configure<JwtOptions>(jwtOptions); 和变体中没有一个只接收一个已经实例化的对象(或者至少没有我见过的)。最后,即使他们这样做了,您也不能使用没有公共无参数构造函数的依赖注入选项类。
public JwtService(IOptions<JwtOptions> jwtOptions)
【问题讨论】:
-
您不能在
FromConfiguration方法中手动执行验证,然后立即调用services.Configure<JwtOptions>(jwtConfiguration)吗?无论如何,内置选项验证并不急切 (github.com/dotnet/extensions/issues/459)。
标签: c# asp.net asp.net-core nullable-reference-types