'Can I use C# 9 records as IOptions?
I have just started playing around with C# 9 and .NET 5.0, specifically the new record
construct. I find I have a lot of excellent use cases for the shorthand syntax of the record types.
One of the use cases I've considered was using a record
for the dto in IOptions<>
, instead of regular classes, for ASP.NET Core applications. These option classes are usually quite plain so I thought it would be a perfect fit, but it seems I cannot get it to work easily, since configuring the application using IOptions<>
requires the object to have a parameterless constructor.
public record MyOptions(string OptionA, int OptionB);
public class Startup
{
public void ConfigureServices(IServiceCollection services) {
services.Configure<MyOptions>(Configuration.GetSection(nameof(MyOptions)));
}
...
}
public class MyController : Controller
{
private readonly MyOptions _options;
public MyController(IOptions<MyOptions> options) {
_options = options.Value; // This throws an exception at runtime
}
}
The example above throws the following exception when attempting to access the IOption<>.Value
property:
System.MissingMethodException: 'No parameterless constructor defined for type 'AcmeSolution.MyOptions'.'
Is there any way to configure the IOptions
configuration system to deserialize the options using the record's constructor instead of requiring a parameterless constructor?
I could use the longhand syntax for the records, but then there's really no benefit over using a class.
Solution 1:[1]
Is there any way to configure the IOptions configuration system to deserialize the options using the record's constructor instead of requiring a parameterless constructor?
No, in general ASP.Net Core uses a lot of run-time type instancing, which requires constructor calls that are known beforehand, and in this case it requires a constructor with no arguments.
You can however make your record class have a parameter-less constructor:
public record MyOptions(string OptionA, int OptionB)
{
public MyOptions(): this(default, default) {}
}
Is it worth it? Eh. Up to you. It's no worse than a regular class, performance-wise, so go with whatever you find clearer!
Edit: alternatively, you should be able to use this form:
public record MyOptions(string OptionA = default, int OptionB = default);
Solution 2:[2]
C# 10
I know the question specifically references C# 9, but if you're living in the present, which I suspect most of you are, this works as expected with C# 10 (ASP.NET Core 6):
public record MyOptions
{
public string MyProperty { get; init; }
}
// ...
builder.Services.Configure<MyOptions>(builder.Configuration);
Solution 3:[3]
Add parameter less constructor
public MyOptions() {}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Blindy |
Solution 2 | Brandon Gano |
Solution 3 | sadiq rashid |