From 3c4ebb506e2d953d14fc8d2ea43b56189349ba19 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:27:06 +0000 Subject: [PATCH 1/4] Initial plan From 9b97f5086b248c2244a4e03a7d0c8e837469b564 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:29:08 +0000 Subject: [PATCH 2/4] Add Riok.Mapperly package Agent-Logs-Url: https://github.com/gothinkster/aspnetcore-realworld-example-app/sessions/1ad5903e-1320-47fb-889d-8728ec9c60ee Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- Directory.Packages.props | 3 ++- src/Conduit/Conduit.csproj | 1 + src/Conduit/packages.lock.json | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 40f95ec..d5b8542 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -9,6 +9,7 @@ + @@ -19,4 +20,4 @@ - + \ No newline at end of file diff --git a/src/Conduit/Conduit.csproj b/src/Conduit/Conduit.csproj index fe9f26f..1379ffc 100644 --- a/src/Conduit/Conduit.csproj +++ b/src/Conduit/Conduit.csproj @@ -6,6 +6,7 @@ + diff --git a/src/Conduit/packages.lock.json b/src/Conduit/packages.lock.json index 5674710..236797c 100644 --- a/src/Conduit/packages.lock.json +++ b/src/Conduit/packages.lock.json @@ -72,6 +72,12 @@ "Microsoft.EntityFrameworkCore.Relational": "10.0.2" } }, + "Riok.Mapperly": { + "type": "Direct", + "requested": "[4.3.1, )", + "resolved": "4.3.1", + "contentHash": "oSE+OVLHyiojrws0QVbQaAT2YKsYbyHqJXPdV7EhGseR/dYgeWS2x1T5qY5I4E+RJkJqMSG+FyZOq4SljWgJWQ==" + }, "Serilog": { "type": "Direct", "requested": "[4.3.0, )", From 6aa1cb30bd03e31bdbdb88701889d3501e5d4254 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:35:36 +0000 Subject: [PATCH 3/4] Replace AutoMapper with Mapperly Agent-Logs-Url: https://github.com/gothinkster/aspnetcore-realworld-example-app/sessions/1ad5903e-1320-47fb-889d-8728ec9c60ee Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- Directory.Packages.props | 1 - src/Conduit/Conduit.csproj | 3 +- src/Conduit/Features/ConduitMapper.cs | 29 +++++++++++++++++++ .../Features/Profiles/MappingProfile.cs | 8 ----- .../Features/Profiles/ProfileReader.cs | 5 ++-- src/Conduit/Features/Users/Create.cs | 5 ++-- src/Conduit/Features/Users/Details.cs | 5 ++-- src/Conduit/Features/Users/Edit.cs | 5 ++-- src/Conduit/Features/Users/Login.cs | 5 ++-- src/Conduit/Features/Users/MappingProfile.cs | 8 ----- src/Conduit/ServicesExtensions.cs | 2 +- src/Conduit/packages.lock.json | 6 ---- .../packages.lock.json | 17 +++++------ 13 files changed, 48 insertions(+), 51 deletions(-) create mode 100644 src/Conduit/Features/ConduitMapper.cs delete mode 100644 src/Conduit/Features/Profiles/MappingProfile.cs delete mode 100644 src/Conduit/Features/Users/MappingProfile.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index d5b8542..493d673 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,6 +1,5 @@ - diff --git a/src/Conduit/Conduit.csproj b/src/Conduit/Conduit.csproj index 1379ffc..aa1b5a0 100644 --- a/src/Conduit/Conduit.csproj +++ b/src/Conduit/Conduit.csproj @@ -1,12 +1,11 @@ - + - diff --git a/src/Conduit/Features/ConduitMapper.cs b/src/Conduit/Features/ConduitMapper.cs new file mode 100644 index 0000000..5e4cd3b --- /dev/null +++ b/src/Conduit/Features/ConduitMapper.cs @@ -0,0 +1,29 @@ +using Conduit.Domain; +using Conduit.Features.Profiles; +using Conduit.Features.Users; +using Riok.Mapperly.Abstractions; + +namespace Conduit.Features; + +[Mapper] +public partial class ConduitMapper +{ + [MapperIgnoreSource(nameof(Person.PersonId))] + [MapperIgnoreSource(nameof(Person.ArticleFavorites))] + [MapperIgnoreSource(nameof(Person.Following))] + [MapperIgnoreSource(nameof(Person.Followers))] + [MapperIgnoreSource(nameof(Person.Hash))] + [MapperIgnoreSource(nameof(Person.Salt))] + [MapperIgnoreTarget(nameof(User.Token))] + public partial User PersonToUser(Person person); + + [MapperIgnoreSource(nameof(Person.PersonId))] + [MapperIgnoreSource(nameof(Person.Email))] + [MapperIgnoreSource(nameof(Person.ArticleFavorites))] + [MapperIgnoreSource(nameof(Person.Following))] + [MapperIgnoreSource(nameof(Person.Followers))] + [MapperIgnoreSource(nameof(Person.Hash))] + [MapperIgnoreSource(nameof(Person.Salt))] + [MapperIgnoreTarget(nameof(Profile.IsFollowed))] + public partial Profile PersonToProfile(Person person); +} diff --git a/src/Conduit/Features/Profiles/MappingProfile.cs b/src/Conduit/Features/Profiles/MappingProfile.cs deleted file mode 100644 index 4c7e2d1..0000000 --- a/src/Conduit/Features/Profiles/MappingProfile.cs +++ /dev/null @@ -1,8 +0,0 @@ -using AutoMapper; - -namespace Conduit.Features.Profiles; - -public class MappingProfile : AutoMapper.Profile -{ - public MappingProfile() => CreateMap(MemberList.None); -} diff --git a/src/Conduit/Features/Profiles/ProfileReader.cs b/src/Conduit/Features/Profiles/ProfileReader.cs index cce9a95..b33fb41 100644 --- a/src/Conduit/Features/Profiles/ProfileReader.cs +++ b/src/Conduit/Features/Profiles/ProfileReader.cs @@ -2,7 +2,6 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using AutoMapper; using Conduit.Infrastructure; using Conduit.Infrastructure.Errors; using Microsoft.EntityFrameworkCore; @@ -12,7 +11,7 @@ namespace Conduit.Features.Profiles; public class ProfileReader( ConduitContext context, ICurrentUserAccessor currentUserAccessor, - IMapper mapper + ConduitMapper mapper ) : IProfileReader { public async Task ReadProfile( @@ -34,7 +33,7 @@ CancellationToken cancellationToken { throw new RestException(HttpStatusCode.NotFound, new { User = Constants.NOT_FOUND }); } - var profile = mapper.Map(person); + var profile = mapper.PersonToProfile(person); if (currentUserName != null) { diff --git a/src/Conduit/Features/Users/Create.cs b/src/Conduit/Features/Users/Create.cs index fe339c1..935c602 100644 --- a/src/Conduit/Features/Users/Create.cs +++ b/src/Conduit/Features/Users/Create.cs @@ -3,7 +3,6 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using AutoMapper; using Conduit.Domain; using Conduit.Infrastructure; using Conduit.Infrastructure.Errors; @@ -34,7 +33,7 @@ public class Handler( ConduitContext context, IPasswordHasher passwordHasher, IJwtTokenGenerator jwtTokenGenerator, - IMapper mapper + ConduitMapper mapper ) : IRequestHandler { public async Task Handle(Command message, CancellationToken cancellationToken) @@ -78,7 +77,7 @@ await context await context.Persons.AddAsync(person, cancellationToken); await context.SaveChangesAsync(cancellationToken); - var user = mapper.Map(person); + var user = mapper.PersonToUser(person); user.Token = jwtTokenGenerator.CreateToken( person.Username ?? throw new InvalidOperationException() ); diff --git a/src/Conduit/Features/Users/Details.cs b/src/Conduit/Features/Users/Details.cs index 9fe133c..3e6e51d 100644 --- a/src/Conduit/Features/Users/Details.cs +++ b/src/Conduit/Features/Users/Details.cs @@ -2,7 +2,6 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using AutoMapper; using Conduit.Infrastructure; using Conduit.Infrastructure.Errors; using Conduit.Infrastructure.Security; @@ -24,7 +23,7 @@ public class QueryValidator : AbstractValidator public class QueryHandler( ConduitContext context, IJwtTokenGenerator jwtTokenGenerator, - IMapper mapper + ConduitMapper mapper ) : IRequestHandler { public async Task Handle(Query message, CancellationToken cancellationToken) @@ -41,7 +40,7 @@ public async Task Handle(Query message, CancellationToken cancella ); } - var user = mapper.Map(person); + var user = mapper.PersonToUser(person); user.Token = jwtTokenGenerator.CreateToken( person.Username ?? throw new InvalidOperationException() ); diff --git a/src/Conduit/Features/Users/Edit.cs b/src/Conduit/Features/Users/Edit.cs index 45a661e..58c4e6b 100644 --- a/src/Conduit/Features/Users/Edit.cs +++ b/src/Conduit/Features/Users/Edit.cs @@ -3,7 +3,6 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using AutoMapper; using Conduit.Infrastructure; using Conduit.Infrastructure.Errors; using Conduit.Infrastructure.Security; @@ -39,7 +38,7 @@ public class Handler( ConduitContext context, IPasswordHasher passwordHasher, ICurrentUserAccessor currentUserAccessor, - IMapper mapper + ConduitMapper mapper ) : IRequestHandler { public async Task Handle(Command message, CancellationToken cancellationToken) @@ -70,7 +69,7 @@ public async Task Handle(Command message, CancellationToken cancel await context.SaveChangesAsync(cancellationToken); - return new UserEnvelope(mapper.Map(person)); + return new UserEnvelope(mapper.PersonToUser(person)); } } } diff --git a/src/Conduit/Features/Users/Login.cs b/src/Conduit/Features/Users/Login.cs index 8b1a07a..cc202b6 100644 --- a/src/Conduit/Features/Users/Login.cs +++ b/src/Conduit/Features/Users/Login.cs @@ -3,7 +3,6 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using AutoMapper; using Conduit.Infrastructure; using Conduit.Infrastructure.Errors; using Conduit.Infrastructure.Security; @@ -38,7 +37,7 @@ public class Handler( ConduitContext context, IPasswordHasher passwordHasher, IJwtTokenGenerator jwtTokenGenerator, - IMapper mapper + ConduitMapper mapper ) : IRequestHandler { public async Task Handle(Command message, CancellationToken cancellationToken) @@ -67,7 +66,7 @@ public async Task Handle(Command message, CancellationToken cancel ); } - var user = mapper.Map(person); + var user = mapper.PersonToUser(person); user.Token = jwtTokenGenerator.CreateToken( person.Username ?? throw new InvalidOperationException() ); diff --git a/src/Conduit/Features/Users/MappingProfile.cs b/src/Conduit/Features/Users/MappingProfile.cs deleted file mode 100644 index 3f289e4..0000000 --- a/src/Conduit/Features/Users/MappingProfile.cs +++ /dev/null @@ -1,8 +0,0 @@ -using AutoMapper; - -namespace Conduit.Features.Users; - -public class MappingProfile : Profile -{ - public MappingProfile() => CreateMap(MemberList.None); -} diff --git a/src/Conduit/ServicesExtensions.cs b/src/Conduit/ServicesExtensions.cs index 0ef3b46..50e0faf 100644 --- a/src/Conduit/ServicesExtensions.cs +++ b/src/Conduit/ServicesExtensions.cs @@ -32,7 +32,7 @@ public static void AddConduit(this IServiceCollection services) services.AddValidatorsFromAssemblyContaining(); - services.AddAutoMapper(typeof(Program)); + services.AddSingleton(); services.AddScoped(); services.AddScoped(); diff --git a/src/Conduit/packages.lock.json b/src/Conduit/packages.lock.json index 236797c..6b07e4e 100644 --- a/src/Conduit/packages.lock.json +++ b/src/Conduit/packages.lock.json @@ -2,12 +2,6 @@ "version": 2, "dependencies": { "net10.0": { - "AutoMapper": { - "type": "Direct", - "requested": "[14.0.0, )", - "resolved": "14.0.0", - "contentHash": "OC+1neAPM4oCCqQj3g2GJ2shziNNhOkxmNB9cVS8jtx4JbgmRzLcUOxB9Tsz6cVPHugdkHgCaCrTjjSI0Z5sCQ==" - }, "FluentValidation": { "type": "Direct", "requested": "[12.0.0, )", diff --git a/tests/Conduit.IntegrationTests/packages.lock.json b/tests/Conduit.IntegrationTests/packages.lock.json index 78dd7a6..407d603 100644 --- a/tests/Conduit.IntegrationTests/packages.lock.json +++ b/tests/Conduit.IntegrationTests/packages.lock.json @@ -458,7 +458,6 @@ "conduit": { "type": "Project", "dependencies": { - "AutoMapper": "[14.0.0, )", "FluentValidation": "[12.0.0, )", "FluentValidation.DependencyInjectionExtensions": "[12.0.0, )", "MediatR": "[12.5.0, )", @@ -466,21 +465,13 @@ "Microsoft.EntityFrameworkCore.InMemory": "[10.0.2, )", "Microsoft.EntityFrameworkCore.SqlServer": "[10.0.2, )", "Microsoft.EntityFrameworkCore.Sqlite": "[10.0.2, )", + "Riok.Mapperly": "[4.3.1, )", "Serilog": "[4.3.0, )", "Serilog.Extensions.Logging": "[8.0.0, )", "Serilog.Sinks.Console": "[6.0.0, )", "Swashbuckle.AspNetCore": "[9.0.6, )" } }, - "AutoMapper": { - "type": "CentralTransitive", - "requested": "[14.0.0, )", - "resolved": "14.0.0", - "contentHash": "OC+1neAPM4oCCqQj3g2GJ2shziNNhOkxmNB9cVS8jtx4JbgmRzLcUOxB9Tsz6cVPHugdkHgCaCrTjjSI0Z5sCQ==", - "dependencies": { - "Microsoft.Extensions.Options": "8.0.0" - } - }, "FluentValidation": { "type": "CentralTransitive", "requested": "[12.0.0, )", @@ -555,6 +546,12 @@ "Microsoft.Extensions.Logging": "10.0.2" } }, + "Riok.Mapperly": { + "type": "CentralTransitive", + "requested": "[4.3.1, )", + "resolved": "4.3.1", + "contentHash": "oSE+OVLHyiojrws0QVbQaAT2YKsYbyHqJXPdV7EhGseR/dYgeWS2x1T5qY5I4E+RJkJqMSG+FyZOq4SljWgJWQ==" + }, "Serilog": { "type": "CentralTransitive", "requested": "[4.3.0, )", From a4cd4541206178ee703d6734e1fb85e78894aa17 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 11:07:24 +0000 Subject: [PATCH 4/4] Merge master into PR branch and resolve conflicts - Keep Mapperly, drop AutoMapper (including updated 16.1.1 from master) - Pick up global.json SDK 10.0.201 update from master - Pick up GitHub Actions workflow update from master - Pick up SliceFixture.cs AddLogging() fix from master - Remove redundant duplicate null check in ProfileReader.cs Agent-Logs-Url: https://github.com/gothinkster/aspnetcore-realworld-example-app/sessions/00567f7d-07a5-41b8-b841-f2512c22ee3f Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- .github/workflows/dotnetcore.yml | 2 +- global.json | 2 +- src/Conduit/Features/Profiles/ProfileReader.cs | 5 ----- tests/Conduit.IntegrationTests/SliceFixture.cs | 1 + 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 9853b1b..39b7ec0 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -11,5 +11,5 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-dotnet@v5 with: - dotnet-version: 10.0.102 + dotnet-version: 10.0.201 - run: dotnet run --project build/build.csproj diff --git a/global.json b/global.json index 3fca435..36a0730 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.102", + "version": "10.0.201", "rollForward": "latestFeature" } } diff --git a/src/Conduit/Features/Profiles/ProfileReader.cs b/src/Conduit/Features/Profiles/ProfileReader.cs index b33fb41..465b663 100644 --- a/src/Conduit/Features/Profiles/ProfileReader.cs +++ b/src/Conduit/Features/Profiles/ProfileReader.cs @@ -28,11 +28,6 @@ CancellationToken cancellationToken { throw new RestException(HttpStatusCode.NotFound, new { User = Constants.NOT_FOUND }); } - - if (person == null) - { - throw new RestException(HttpStatusCode.NotFound, new { User = Constants.NOT_FOUND }); - } var profile = mapper.PersonToProfile(person); if (currentUserName != null) diff --git a/tests/Conduit.IntegrationTests/SliceFixture.cs b/tests/Conduit.IntegrationTests/SliceFixture.cs index f81d25a..9f43de2 100644 --- a/tests/Conduit.IntegrationTests/SliceFixture.cs +++ b/tests/Conduit.IntegrationTests/SliceFixture.cs @@ -17,6 +17,7 @@ public class SliceFixture : IDisposable public SliceFixture() { var services = new ServiceCollection(); + services.AddLogging(); services.AddConduit(); var builder = new DbContextOptionsBuilder();