Skip to content

Commit 104a192

Browse files
authored
Merge pull request #4278 from AutoMapper/DI
Add the DI code
2 parents d0ed291 + 8960bee commit 104a192

20 files changed

+1206
-0
lines changed

AutoMapper.sln

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoMapper.UnitTests", "src
2626
EndProject
2727
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoMapper.IntegrationTests", "src\IntegrationTests\AutoMapper.IntegrationTests.csproj", "{24B47F4C-0035-4F29-AAD9-4C47E1AAD98E}"
2828
EndProject
29+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoMapper.DI.Tests", "src\AutoMapper.Extensions.Microsoft.DependencyInjection.Tests\AutoMapper.DI.Tests.csproj", "{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}"
30+
EndProject
31+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp", "src\TestApp\TestApp.csproj", "{35CED3AE-B825-4703-992D-A58B5BE646DC}"
32+
EndProject
2933
Global
3034
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3135
Debug|Any CPU = Debug|Any CPU
@@ -96,6 +100,38 @@ Global
96100
{24B47F4C-0035-4F29-AAD9-4C47E1AAD98E}.Release|x64.Build.0 = Release|Any CPU
97101
{24B47F4C-0035-4F29-AAD9-4C47E1AAD98E}.Release|x86.ActiveCfg = Release|Any CPU
98102
{24B47F4C-0035-4F29-AAD9-4C47E1AAD98E}.Release|x86.Build.0 = Release|Any CPU
103+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
104+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|Any CPU.Build.0 = Debug|Any CPU
105+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|ARM.ActiveCfg = Debug|Any CPU
106+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|ARM.Build.0 = Debug|Any CPU
107+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|x64.ActiveCfg = Debug|Any CPU
108+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|x64.Build.0 = Debug|Any CPU
109+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|x86.ActiveCfg = Debug|Any CPU
110+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Debug|x86.Build.0 = Debug|Any CPU
111+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|Any CPU.ActiveCfg = Release|Any CPU
112+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|Any CPU.Build.0 = Release|Any CPU
113+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|ARM.ActiveCfg = Release|Any CPU
114+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|ARM.Build.0 = Release|Any CPU
115+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|x64.ActiveCfg = Release|Any CPU
116+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|x64.Build.0 = Release|Any CPU
117+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|x86.ActiveCfg = Release|Any CPU
118+
{BEBD620A-8BAA-463F-BE0F-8319AD3C1644}.Release|x86.Build.0 = Release|Any CPU
119+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
120+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
121+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|ARM.ActiveCfg = Debug|Any CPU
122+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|ARM.Build.0 = Debug|Any CPU
123+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|x64.ActiveCfg = Debug|Any CPU
124+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|x64.Build.0 = Debug|Any CPU
125+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|x86.ActiveCfg = Debug|Any CPU
126+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Debug|x86.Build.0 = Debug|Any CPU
127+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
128+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|Any CPU.Build.0 = Release|Any CPU
129+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|ARM.ActiveCfg = Release|Any CPU
130+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|ARM.Build.0 = Release|Any CPU
131+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|x64.ActiveCfg = Release|Any CPU
132+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|x64.Build.0 = Release|Any CPU
133+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|x86.ActiveCfg = Release|Any CPU
134+
{35CED3AE-B825-4703-992D-A58B5BE646DC}.Release|x86.Build.0 = Release|Any CPU
99135
EndGlobalSection
100136
GlobalSection(SolutionProperties) = preSolution
101137
HideSolutionNode = FALSE

docs/13.0-Upgrade-Guide.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
## AutoMapper now targets .Net 6
66

7+
## `AddAutoMapper` is part of the core package and the DI package is discontinued
8+
79
## `IMapper` has nullable annotations
810

911
Besides the build-time impact, there is also a behaviour change. Non-generic `Map` overloads require now either a destination type or a non-null destination object.

docs/Dependency-injection.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
There is a [NuGet package](https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/) to be used with the default injection mechanism described [here](https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection) and used in [this project](https://github.com/jbogard/ContosoUniversityCore/blob/master/src/ContosoUniversityCore/Startup.cs).
88

9+
Starting with version 13.0, `AddAutoMapper` is part of the core package and the DI package is discontinued.
10+
911
You define the configuration using [profiles](Configuration.html#profile-instances). And then you let AutoMapper know in what assemblies are those profiles defined by calling the `IServiceCollection` extension method `AddAutoMapper` at startup:
1012
```c#
1113
services.AddAutoMapper(profileAssembly1, profileAssembly2 /*, ...*/);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
3+
namespace AutoMapper.Extensions.Microsoft.DependencyInjection.Tests
4+
{
5+
using System;
6+
using AutoMapper.Internal;
7+
using Shouldly;
8+
using Xunit;
9+
10+
public class AppDomainResolutionTests
11+
{
12+
private readonly IServiceProvider _provider;
13+
14+
public AppDomainResolutionTests()
15+
{
16+
IServiceCollection services = new ServiceCollection();
17+
services.AddAutoMapper(typeof(AppDomainResolutionTests));
18+
_provider = services.BuildServiceProvider();
19+
}
20+
21+
[Fact]
22+
public void ShouldResolveConfiguration()
23+
{
24+
_provider.GetService<IConfigurationProvider>().ShouldNotBeNull();
25+
}
26+
27+
[Fact]
28+
public void ShouldConfigureProfiles()
29+
{
30+
_provider.GetService<IConfigurationProvider>().Internal().GetAllTypeMaps().Count.ShouldBe(4);
31+
}
32+
33+
[Fact]
34+
public void ShouldResolveMapper()
35+
{
36+
_provider.GetService<IMapper>().ShouldNotBeNull();
37+
}
38+
}
39+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
3+
namespace AutoMapper.Extensions.Microsoft.DependencyInjection.Tests
4+
{
5+
using System;
6+
using System.Reflection;
7+
using AutoMapper.Internal;
8+
using Shouldly;
9+
using Xunit;
10+
11+
public class AssemblyResolutionTests
12+
{
13+
private static readonly IServiceProvider _provider;
14+
15+
static AssemblyResolutionTests()
16+
{
17+
_provider = BuildServiceProvider();
18+
}
19+
20+
private static ServiceProvider BuildServiceProvider()
21+
{
22+
IServiceCollection services = new ServiceCollection();
23+
services.AddAutoMapper(typeof(Source).GetTypeInfo().Assembly);
24+
var serviceProvider = services.BuildServiceProvider();
25+
return serviceProvider;
26+
}
27+
28+
[Fact]
29+
public void ShouldResolveConfiguration()
30+
{
31+
_provider.GetService<IConfigurationProvider>().ShouldNotBeNull();
32+
}
33+
34+
[Fact]
35+
public void ShouldConfigureProfiles()
36+
{
37+
_provider.GetService<IConfigurationProvider>().Internal().GetAllTypeMaps().Count.ShouldBe(4);
38+
}
39+
40+
[Fact]
41+
public void ShouldResolveMapper()
42+
{
43+
_provider.GetService<IMapper>().ShouldNotBeNull();
44+
}
45+
46+
[Fact]
47+
public void CanRegisterTwiceWithoutProblems()
48+
{
49+
new Action(() => BuildServiceProvider()).ShouldNotThrow();
50+
}
51+
}
52+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Shouldly;
4+
using Xunit;
5+
6+
namespace AutoMapper.Extensions.Microsoft.DependencyInjection.Tests
7+
{
8+
public class AttributeTests
9+
{
10+
[Fact]
11+
public void Should_not_register_static_instance_when_configured()
12+
{
13+
IServiceCollection services = new ServiceCollection();
14+
services.AddAutoMapper(typeof(Source3));
15+
16+
var serviceProvider = services.BuildServiceProvider();
17+
18+
var mapper = serviceProvider.GetService<IMapper>();
19+
20+
var source = new Source3 {Value = 3};
21+
22+
var dest = mapper.Map<Dest3>(source);
23+
24+
dest.Value.ShouldBe(source.Value);
25+
}
26+
}
27+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net7.0</TargetFrameworks>
5+
<PreserveCompilationContext>true</PreserveCompilationContext>
6+
<AssemblyName>AutoMapper.Extensions.Microsoft.DependencyInjection.Tests</AssemblyName>
7+
<PackageId>AutoMapper.Extensions.Microsoft.DependencyInjection.Tests</PackageId>
8+
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
9+
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
10+
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
11+
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<ProjectReference Include="..\AutoMapper\AutoMapper.csproj" />
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
20+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" PrivateAssets="All" />
21+
<PackageReference Include="Shouldly" Version="4.1.0" />
22+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
23+
<PackageReference Include="xunit" Version="2.4.2" />
24+
</ItemGroup>
25+
26+
</Project>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
namespace AutoMapper.Extensions.Microsoft.DependencyInjection.Tests
2+
{
3+
using System;
4+
using global::Microsoft.Extensions.DependencyInjection;
5+
using Shouldly;
6+
using Xunit;
7+
8+
public class DependencyTests
9+
{
10+
private readonly IServiceProvider _provider;
11+
12+
public DependencyTests()
13+
{
14+
IServiceCollection services = new ServiceCollection();
15+
services.AddTransient<ISomeService>(sp => new FooService(5));
16+
services.AddAutoMapper(typeof(Source), typeof(Profile));
17+
_provider = services.BuildServiceProvider();
18+
19+
_provider.GetService<IConfigurationProvider>().AssertConfigurationIsValid();
20+
}
21+
22+
[Fact]
23+
public void ShouldResolveWithDependency()
24+
{
25+
var mapper = _provider.GetService<IMapper>();
26+
var dest = mapper.Map<Source2, Dest2>(new Source2());
27+
28+
dest.ResolvedValue.ShouldBe(5);
29+
}
30+
31+
[Fact]
32+
public void ShouldConvertWithDependency()
33+
{
34+
var mapper = _provider.GetService<IMapper>();
35+
var dest = mapper.Map<Source2, Dest2>(new Source2 { ConvertedValue = 5});
36+
37+
dest.ConvertedValue.ShouldBe(10);
38+
}
39+
}
40+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.DependencyInjection.Extensions;
3+
using Shouldly;
4+
using Xunit;
5+
6+
namespace AutoMapper.Extensions.Microsoft.DependencyInjection.Tests.Integrations
7+
{
8+
public class ServiceLifetimeTests
9+
{
10+
internal interface ISingletonService
11+
{
12+
Bar DoTheThing(Foo theObj);
13+
}
14+
15+
internal class TestSingletonService : ISingletonService
16+
{
17+
private readonly IMapper _mapper;
18+
19+
public TestSingletonService(IMapper mapper)
20+
{
21+
_mapper = mapper;
22+
}
23+
24+
public Bar DoTheThing(Foo theObj)
25+
{
26+
var bar = _mapper.Map<Bar>(theObj);
27+
return bar;
28+
}
29+
}
30+
31+
internal class Foo
32+
{
33+
public int TheValue { get; set; }
34+
}
35+
36+
internal class Bar
37+
{
38+
public int TheValue { get; set; }
39+
}
40+
41+
42+
[Fact]
43+
public void CanUseDefaultInjectedIMapperInSingletonService()
44+
{
45+
//arrange
46+
var services = new ServiceCollection();
47+
services.TryAddSingleton<ISingletonService, TestSingletonService>();
48+
services.AddAutoMapper(cfg => cfg.CreateMap<Foo, Bar>().ReverseMap(), GetType().Assembly);
49+
var sp = services.BuildServiceProvider();
50+
Bar actual;
51+
52+
//act
53+
using (var scope = sp.CreateScope())
54+
{
55+
var service = scope.ServiceProvider.GetService<ISingletonService>();
56+
actual = service.DoTheThing(new Foo{TheValue = 1});
57+
}
58+
59+
//assert
60+
actual.ShouldNotBeNull();
61+
actual.TheValue.ShouldBe(1);
62+
}
63+
}
64+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System.Linq;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Shouldly;
4+
using Xunit;
5+
6+
namespace AutoMapper.Extensions.Microsoft.DependencyInjection.Tests
7+
{
8+
public class MultipleRegistrationTests
9+
{
10+
[Fact]
11+
public void Can_register_multiple_times()
12+
{
13+
var services = new ServiceCollection();
14+
15+
services.AddAutoMapper(cfg => { });
16+
services.AddAutoMapper(cfg => { });
17+
services.AddAutoMapper(cfg => { });
18+
19+
var serviceProvider = services.BuildServiceProvider();
20+
21+
serviceProvider.GetService<IMapper>().ShouldNotBeNull();
22+
}
23+
24+
[Fact]
25+
public void Can_register_assembly_multiple_times()
26+
{
27+
var services = new ServiceCollection();
28+
29+
services.AddAutoMapper(typeof(MultipleRegistrationTests));
30+
services.AddAutoMapper(typeof(MultipleRegistrationTests));
31+
services.AddAutoMapper(typeof(MultipleRegistrationTests));
32+
services.AddTransient<ISomeService, MutableService>();
33+
34+
var serviceProvider = services.BuildServiceProvider();
35+
36+
serviceProvider.GetService<IMapper>().ShouldNotBeNull();
37+
serviceProvider.GetService<DependencyValueConverter>().ShouldNotBeNull();
38+
serviceProvider.GetServices<DependencyValueConverter>().Count().ShouldBe(1);
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)