-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AddOption/Service.Configure creating duplicated entries #38569
Comments
Thanks for contacting us. |
This is the result of how WebApplicationBuilder currently shares service descriptors with the underlying HostBuilder. I recently opened dotnet/runtime#61635 to improve this integration in .NET 7. I think we'll want to share the IServiceCollection more directly going forward. AddOptions wouldn't normally ever add service descriptors more than once, but WebApplicationBuilder effectively calls AddOptions on two different IServiceCollections and merges these collections together. I'm a little surprised you found this @jhonathanalmeida. Why are the apps trying to resolve Stacks where AddOptions is called
|
Hey @halter73, thanks for sharing that info! Our real life scenario is actually a bit more complex. We are developing a shared library for our internal developers, and a few of the implementations we have for instance, for Azure KeyVault, or Azure ServiceBus, we rely on injecting the configuration using AddOptions. The thing is, one of the teams needed to actually access two different instances of the service bus, in the same application, so we tried to use named injections, which .Net 5 DI does not allow right? So what we did is, we created Identifiable Configurations. This is done by having a IIdentifiableConfiguration interface, like:
And then each injection will have this value set to it's respective "ConfigurationName ", so each service/instance can retrieve their own version of the configuration. To exemplify, let's say we have a DBSettings class, and I need multiple injections of if, because my App need to connect to two different DBs. So DBSettings implements this interface, and we get:
And then, we would have something like this in the AppSettings:
And then we would have these injections:
And finally in the Service we would have:
This way, each service can identify it's own instance of the configuration. I know it is a bit messy, I'll create a realish example, and push it to the Repo above. |
Ok, just pushed another example containing a somewhat similar approach to what we are doing. You can find the code in this project (under the solution/repo above). However I'd like to highlight two points. Just for reference, this pattern of option injection we were using was working fine on .Net 5. Also, just to give you some more info, in our real implementation, there are also two instances of the same object injected, for example a DBClient, so in order to identify them, each one is injected with a identification as well, and this is done pretty similarly to what we did with the Configurations, by implementing a IIdentifiableObject interface, which has a Key, which is then injected in the instance by a factory patter. We just found out that named option Injections exists, but I don't think named injections exists, do they? So I can inject multiple instances of the same class/service? Thanks once again for all the help/information. Best regards Jhonny |
Glad to hear this! Named options do seem like the right approach here.
This is by design. The same thing should happen in .NET 5.
Correct. Named services aren't a concept that's built in to Microsoft.Extensions.DependencyInjection. We recommend using the factory pattern if you want named services similar to what we do with
Do you have an example project demonstrating the pattern you're trying to use working in .NET 5? I think that would better help me understand the scenario. I don't think calling AddOptions multiple times should have ever added more than one |
This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes. See our Issue Management Policies for more information. |
Describe the bug
When injecting settings on WebApplication Builder, 2 instances of the same injections are made:
builder.Services.Configure<MySettings>(builder.Configuration.GetSection("MySettings"));
OR
builder.Services.AddOptions<MySettings>().Bind(builder.Configuration.GetSection("MySettings"));
This only happens when using the WebApplication Builder, but works fine when using the old Generic Host through Program.Main + Startup file.
P.S. Found this behavior when migrating a new project from .Net5 to .Net6.
To Reproduce
Issue can be reproduced by using the following solution: https://github.com/jhonathanalmeida/DotNet6_AddOption_Test
There are two projects, one testing with GRPC and other with REST/Web.
In both projects you can see that there is only one injection of the settings, such as:
builder.Services.AddOptions<MySettings>().Bind(builder.Configuration.GetSection("MySettings"));
And then, once the application is running, you can call either the "WeatherForecastController" or "GreeterService", and during the constructor call you will see that it will log an error as it has more then one item in the list, and then throw the "InvalidOperationException" with the message " Sequence contains more than one element".
Exceptions (if any)
The exception occurs when calling the
IEnumerable<IOptions<MySettings>> mySettings
.Single().Value.Further technical details
dotnet --info
:.NET SDK (reflecting any global.json):
Version: 6.0.100
Commit: 9e8b04bbff
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19043
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\6.0.100\
Host (useful for support):
Version: 6.0.0
Commit: 4822e3c3aa
.NET SDKs installed:
5.0.402 [C:\Program Files\dotnet\sdk]
6.0.100 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.All 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
The text was updated successfully, but these errors were encountered: