Skip to content
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

.NET 6 Simple Injector has error of the call is ambiguous between SimpleInjectorGenericHostExtensions and SimpleInjectorUseOptionsAspNetCoreExtensions #933

Closed
funkel1989 opened this issue Nov 28, 2021 · 5 comments
Labels

Comments

@funkel1989
Copy link

funkel1989 commented Nov 28, 2021

Started a new .NET 6 web API project today and when implementing Simple Injector similar to a way that is worked in a previous .NET 5 web api project i received the following error when calling app.UseSimpleInjector(container);

Error:

Error CS0121 The call is ambiguous between the following methods or properties: 'SimpleInjector.SimpleInjectorGenericHostExtensions.UseSimpleInjector(Microsoft.Extensions.Hosting.IHost, SimpleInjector.Container)' and 'SimpleInjector.SimpleInjectorUseOptionsAspNetCoreExtensions.UseSimpleInjector(Microsoft.AspNetCore.Builder.IApplicationBuilder, SimpleInjector.Container)'

Project Dependencies:

  <ItemGroup>
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
    <PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
    <PackageReference Include="FluentValidation.AspNetCore" Version="10.3.4" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.14.0" />
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.0" />
    <PackageReference Include="RockLib.Logging" Version="3.0.8" />
    <PackageReference Include="RockLib.Logging.AspNetCore" Version="3.2.4" />
    <PackageReference Include="SimpleInjector.Integration.AspNetCore.Mvc.Core" Version="5.3.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  </ItemGroup>

I've tried using the SimpleInjector Package without the Mvc.Core integration but that doesn't seem to work. I'm unsure where the ambiguity is coming from. Any help would be appreciated.

Program.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SimpleInjector;
using SimpleInjector.Lifestyles;
using Container = SimpleInjector.Container;

var builder = WebApplication.CreateBuilder(args);

IConfiguration configuration = builder.Configuration;

Container container = new Container();
container.Options.DefaultLifestyle = Lifestyle.Scoped;
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

builder.Services.AddMvc();
builder.Services.AddHealthChecks();

builder.Services.AddSimpleInjector(container, options =>
{
    options.AddAspNetCore().AddControllerActivation();
    options.AddLogging();
});

builder.Services.BaseConfiguration(configuration)
    .AddVersioningConfiguration()
    .InitializeContainer(configuration, container)
    .ConfigureModelBindingExceptionHandling(container)
    .AddSwaggerDocumentation()
    .AddCustomDbConfiguration(configuration);

var app = builder.Build();

var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
app.UseSimpleInjector(container);  // <<< This is what is ambiguious
@funkel1989
Copy link
Author

So it looks like in .NET 6 builder.Build() Returns a Type of WebApplication instead of IApplicationBuilder. WebApplication must contain other extension methods that conflict with SimpleInjector?

I fixed this by abstraction app.UseCors into an extension method that returned IApplicationBuilder and than chained UseSimpleIngector(Container); to the end of that. Still working through other issues before I can determine if this works as a workaround but it compiles. See below for code.

UseCustomCors:

public static IApplicationBuilder UseCustomCors(this IApplicationBuilder app)
    {
        app.UseCors(Constants.CorPolicyName);

        return app;
    }

Program.cs

var app = builder.Build();

var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
app.UseCustomCors().UseSimpleInjector(container);

One thing to note, if you do IApplicationBuilder app = builder.Build(); this will work for everything still but removes the ability to do the app.Services.GetRequiredService that I need to do using this new .NET 6 Pattern.

@funkel1989
Copy link
Author

Can confirm. The above resolves the problem and everything seems to function as expected but you should consider this issue as a bug IMO as this isn't a workaround someone should have to do.

@dotnetjunkie
Copy link
Collaborator

dotnetjunkie commented Dec 1, 2021

Change this line:

app.UseSimpleInjector(container);

to the following:

app.Services.UseSimpleInjector(container);

I reflected this in the documentation to allow the documentation to work with all versions of ASP.NET Core.


Let me explain why the call to app.UseSimpleInjector(container) causes a compile error.

The new Build() method of the WebApplicationBuilder class has a return type of WebApplication. This WebApplication is new in .NET 6, and it implements both IHost and IApplicationBuilder. This is unfortunate, because the Simple Injector integration packages contain helpful extension methods named UseSimpleInjector for both IHost and IApplicationBuilder. Because WebApplication implements both interfaces, it causes the C# compiler to show the "ambiguous call" (CS0121) compilation error. The compiler simply can't decide which extension method to pick (although in practice it wouldn't make a difference which method it would pick in our case).

The problem could be solved by adding -yet another- extension method, but now directly on WebApplication. Because WebApplication is new in .NET 6, however, it would cause the Simple Injector integration packages to no longer work under earlier releases, which is not an option. That's why a suggest using the solution above, and this is why I updated the documentation to reflect this.

@dotnetjunkie
Copy link
Collaborator

The new project template for ASP.NET Core 6 contains a 'simplified' bootstrapper where Program and Startup class are merged into a single file. That single file contains no namespaces, no class or method bodies.

Below is an example that shows how to integrate Simple Injector in to a ASP.NET Core 6 MVC application, that uses this new template This code is the exact same integration as the example in the documentation:

// Program.cs
// Used NuGet Packages: SimpleInjector + SimpleInjector.Integration.AspNetCore.Mvc
using SimpleInjector;

var container = new Container();

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
var services = builder.Services;

services.AddControllersWithViews();

services.AddLogging();
services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddSimpleInjector(container, options =>
{
    options.AddAspNetCore()
        .AddControllerActivation()
        .AddViewComponentActivation()
        .AddPageModelActivation()
        .AddTagHelperActivation();

    options.AddLogging();
    options.AddLocalization();
});

InitializeContainer();

void InitializeContainer()
{
    container.Register<IUserService, UserService>(Lifestyle.Singleton);
}

WebApplication app = builder.Build();

app.Services.UseSimpleInjector(container);

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseMiddleware<CustomMiddleware1>(container);
app.UseMiddleware<CustomMiddleware2>(container);

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

container.Verify();

app.Run();

This was referenced Dec 1, 2021
@funkel1989
Copy link
Author

Thanks a lot for the information this post provides. This works great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants