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

Migrate Autofac DI -> Native DI in Asp.Net Core #701

Merged
merged 9 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 0 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
<PackageVersion Include="Ardalis.SmartEnum" Version="8.0.0" />
<PackageVersion Include="Ardalis.Specification" Version="8.0.0" />
<PackageVersion Include="Ardalis.Specification.EntityFrameworkCore" Version="8.0.0" />
<PackageVersion Include="Autofac" Version="8.0.0" />
<PackageVersion Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.1" />
<PackageVersion Include="FastEndpoints" Version="5.23.0" />
<PackageVersion Include="FastEndpoints.ApiExplorer" Version="2.2.0" />
Expand Down
1 change: 0 additions & 1 deletion src/Clean.Architecture.Core/Clean.Architecture.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<PackageReference Include="Ardalis.SharedKernel" />
<PackageReference Include="Ardalis.SmartEnum" />
<PackageReference Include="Ardalis.Specification" />
<PackageReference Include="Autofac" />
<PackageReference Include="MediatR" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
</ItemGroup>
Expand Down
17 changes: 0 additions & 17 deletions src/Clean.Architecture.Core/DefaultCoreModule.cs

This file was deleted.

134 changes: 0 additions & 134 deletions src/Clean.Architecture.Infrastructure/AutofacInfrastructureModule.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
<ItemGroup>
<PackageReference Include="Ardalis.SharedKernel" />
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" />
<PackageReference Include="Autofac" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" />
<PackageReference Include="MailKit" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" PrivateAssets="all" />
Expand Down
2 changes: 1 addition & 1 deletion src/Clean.Architecture.Infrastructure/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Infrastructure should depend on Core (and, optionally, Use Cases) where abstract

Infrastructure classes implement interfaces found in the Core (Use Cases) project(s).

These implementations are wired up at startup using DI. In this case using Autofac and the Module classes defined in each project.
These implementations are wired up at startup using DI. In this case using `Microsoft.Extensions.DependencyInjection` and extension methods defined in each project.

Need help? Check out the sample here:
https://github.com/ardalis/CleanArchitecture/tree/main/sample
Expand Down
71 changes: 60 additions & 11 deletions src/Clean.Architecture.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
using Ardalis.GuardClauses;
using System.Reflection;
using Ardalis.GuardClauses;
using Ardalis.ListStartupServices;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Clean.Architecture.Core;
using Ardalis.SharedKernel;
using Clean.Architecture.Core.ContributorAggregate;
using Clean.Architecture.Core.Interfaces;
using Clean.Architecture.Core.Services;
using Clean.Architecture.Infrastructure;
using Clean.Architecture.Infrastructure.Data;
using Clean.Architecture.Infrastructure.Data.Queries;
using Clean.Architecture.Infrastructure.Email;
using Clean.Architecture.UseCases.Contributors.Create;
using Clean.Architecture.UseCases.Contributors.List;
using FastEndpoints;
using FastEndpoints.Swagger;
using MediatR;
using MediatR.Pipeline;
using Serilog;

var logger = Serilog.Log.Logger = new LoggerConfiguration()
Expand All @@ -18,8 +26,6 @@

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

builder.Host.UseSerilog((_, config) => config.ReadFrom.Configuration(builder.Configuration));

builder.Services.Configure<CookiePolicyOptions>(options =>
Expand Down Expand Up @@ -47,12 +53,55 @@
config.Path = "/listservices";
});

var assemblies = new[]
{
Assembly.GetAssembly(typeof(Contributor)),
Assembly.GetAssembly(typeof(CreateContributorCommand))
};

builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
var mediatrOpenTypes = new[]
{
containerBuilder.RegisterModule(new DefaultCoreModule());
containerBuilder.RegisterModule(new AutofacInfrastructureModule(builder.Environment.IsDevelopment()));
});
typeof(IRequestHandler<,>),
typeof(IRequestExceptionHandler<,,>),
typeof(IRequestExceptionAction<,>),
typeof(INotificationHandler<>),
};

foreach (var assembly in assemblies)
{
foreach (var openInterfaceType in mediatrOpenTypes)
{
if (assembly != null)
{
assembly.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == openInterfaceType))
.ToList()
.ForEach(implementationType =>
{
var serviceType = implementationType.GetInterfaces().First(i => i.IsGenericType && i.GetGenericTypeDefinition() == openInterfaceType);
builder.Services.AddScoped(serviceType, implementationType);
});
}
}
}

Comment on lines +62 to +86
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this loop be removed in favor of using MediatR's own DI registration method?

builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(assemblies));

builder.Services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
builder.Services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should clean this up.

I wrote a blog post on this topic.

In Program.cs builder is in scope wherever you use it.

builder.Services.AddScoped<IListContributorsQueryService, ListContributorsQueryService>();
builder.Services.AddScoped<IMediator, Mediator>();
builder.Services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
builder.Services.AddScoped<IDomainEventDispatcher, MediatRDomainEventDispatcher>();
builder.Services.AddScoped<IListContributorsQueryService, ListContributorsQueryService>();
builder.Services.AddScoped<IDeleteContributorService, DeleteContributorService>();

if (builder.Environment.IsDevelopment())
{
builder.Services.AddScoped<IEmailSender, FakeEmailSender>();
}
else
{
builder.Services.AddScoped<IEmailSender, SmtpEmailSender>();
}

var app = builder.Build();

Expand Down Expand Up @@ -83,7 +132,7 @@ static void SeedDatabase(WebApplication app)
try
{
var context = services.GetRequiredService<AppDbContext>();
// context.Database.Migrate();
// context.Database.Migrate();
context.Database.EnsureCreated();
SeedData.Initialize(services);
}
Expand Down