Skip to content

Commit ad5a6f8

Browse files
authored
Merge pull request #3596 from AutoMapper/upgrade_guide
11.0 upgrade guide
2 parents bdc0120 + fbffc7a commit ad5a6f8

File tree

298 files changed

+2305
-2253
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

298 files changed

+2305
-2253
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
build:
1212
strategy:
1313
fail-fast: false
14-
runs-on: windows-latest
14+
runs-on: windows-2022
1515
steps:
1616
- name: Checkout
1717
uses: actions/checkout@v2

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
build:
99
strategy:
1010
fail-fast: false
11-
runs-on: windows-latest
11+
runs-on: windows-2022
1212
steps:
1313
- name: Checkout
1414
uses: actions/checkout@v2

AutoMapper.sln

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1010
CONTRIBUTING.md = CONTRIBUTING.md
1111
Directory.Build.props = Directory.Build.props
1212
ISSUE_TEMPLATE.md = ISSUE_TEMPLATE.md
13+
nuget.config = nuget.config
1314
Push.ps1 = Push.ps1
1415
README.md = README.md
1516
.github\workflows\release.yml = .github\workflows\release.yml
@@ -36,6 +37,7 @@ Global
3637
EndGlobalSection
3738
GlobalSection(ProjectConfigurationPlatforms) = postSolution
3839
{B8051389-CB47-46FB-B234-9D49506704AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40+
{B8051389-CB47-46FB-B234-9D49506704AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
3941
{B8051389-CB47-46FB-B234-9D49506704AA}.Debug|ARM.ActiveCfg = Debug|Any CPU
4042
{B8051389-CB47-46FB-B234-9D49506704AA}.Debug|x64.ActiveCfg = Debug|Any CPU
4143
{B8051389-CB47-46FB-B234-9D49506704AA}.Debug|x86.ActiveCfg = Debug|Any CPU

ISSUE_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!--
22
33
If you're new to AutoMapper, please ask a question on StackOverflow first and come back here if the people there consider it a bug.
4-
If you've just upgraded to 10.0, please read the upgrade guide first (https://docs.automapper.org/en/latest/10.0-Upgrade-Guide.html).
4+
If you've just upgraded to 11.0, please read the upgrade guide first (https://docs.automapper.org/en/latest/11.0-Upgrade-Guide.html).
55
Try the [MyGet](https://docs.automapper.org/en/latest/The-MyGet-build.html) build.
66
Try to provide [a minimal, complete, and verifiable example](https://stackoverflow.com/help/mcve), preferably a [gist](https://gist.github.com/lbargaoanu/9c7233441c3a3413cc2b9b9ebb5964a9) that we can execute and see fail. [Here](https://gist.github.com/lbargaoanu/0cbc531306223f7ffc5468becf2642d6) is an example for ProjectTo.
77
For feature requests, just clear out the below.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<img src="https://s3.amazonaws.com/automapper/logo.png" alt="AutoMapper">
1+
![AutoMapper](https://s3.amazonaws.com/automapper/logo.png)
22

33
[![CI](https://github.com/automapper/automapper/workflows/CI/badge.svg)](https://github.com/AutoMapper/AutoMapper/actions?query=workflow%3ACI)
4-
[![NuGet](http://img.shields.io/nuget/v/AutoMapper.svg)](https://www.nuget.org/packages/AutoMapper/)
5-
[![MyGet (dev)](https://img.shields.io/myget/automapperdev/v/AutoMapper.svg)](https://myget.org/feed/automapperdev/package/nuget/AutoMapper)
4+
[![NuGet](http://img.shields.io/nuget/vpre/AutoMapper.svg?label=NuGet)](https://www.nuget.org/packages/AutoMapper/)
5+
[![MyGet (dev)](https://img.shields.io/myget/automapperdev/vpre/AutoMapper.svg?label=MyGet)](https://myget.org/feed/automapperdev/package/nuget/AutoMapper)
66

77
### What is AutoMapper?
88

docs/11.0-Upgrade-Guide.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
[Release notes](https://github.com/AutoMapper/AutoMapper/releases/tag/v11.0.0).
44

5+
## AutoMapper now targets .Net Standard 2.1 and doesn't work on .Net Framework
6+
7+
## `ForAllMaps`, `ForAllPropertyMaps`, `Advanced` and other "missing" APIs
8+
9+
Some APIs were hidden for normal usage. To light them up, you need to add an `using` for `AutoMapper.Internal` and call the [`Internal` extension method](https://github.com/AutoMapper/AutoMapper/blob/9f2f16067ab201a5a8b9bc982f3a37e8790da7a0/src/AutoMapper/Internal/InternalApi.cs#L15) on the configuration object.
10+
Most users don't need these advanced methods. Some expose internals and are not subject to the usual semantic versioning rules. To avoid such tight coupling to AutoMapper, you should try to stick to the public API.
11+
512
## Mapping _into_ existing collections
613

714
When calling `Map` with an existing readonly collection, such as `IEnumerable<>`, the setter will be used to replace it. If you actually have to map _into_ that collection, you need to change its type to a writable
@@ -21,7 +28,7 @@ That was misleading for a lot of people. You can opt-in per map with `AsProxy` (
2128

2229
## `MapToAttribute` and `IgnoreMapAttribute` were removed
2330

24-
These were older attributes, unrelated to the newer attributes API. You can switch to the fluent API or implement the attributes in your own code. Check the tests for an example.
31+
These were older attributes, unrelated to the newer attributes API. You can switch to the fluent API or implement the attributes in your own code. Check the tests for sample code ([here](https://github.com/AutoMapper/AutoMapper/search?q=MapToAttribute) and [here](https://github.com/AutoMapper/AutoMapper/search?q=IgnoreMapAttribute)).
2532

2633
## Global pre and postfixes are now applied in all maps
2734

@@ -30,3 +37,11 @@ They used to be applied only in the global configuration, now they are applied i
3037
## `ForAllOtherMembers` was removed
3138

3239
That was used to disable mapping by convention, not something we want to support. When only used for validation, it can be replaced with `MemberList.None`.
40+
41+
## C# Indexers (`Item` property)
42+
43+
These used to be ignored by default, but that's expensive and most types don't have them. So you have to explicitly ignore them. Globally, with `ShouldMapProperty` or `GlobalIgnores`, or per member.
44+
45+
## Configuration performance
46+
47+
While you should get improvements without code changes, you can do even better. Definitely use `CreateProjection` with `ProjectTo`. If you're an advanced user and you're confident in your test coverage, you can [disable](https://gist.github.com/lbargaoanu/9948bf66d452ba6b816252f9965143ee) any features you don't need. Needless to say, do measure to see if these help in your particular case.

docs/Configuration-validation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@ To skip validation altogether for this map, use `MemberList.None`.
5555

5656
## Custom validations
5757

58-
You can add custom validations through an extension point. See [here](https://github.com/AutoMapper/AutoMapper/blob/7a00700de61cd3234b6a6eb4bf0f6bbe402369b1/src/UnitTests/ConfigurationValidation.cs#L30).
58+
You can add custom validations through an extension point. See [here](https://github.com/AutoMapper/AutoMapper/blob/bdc0120497d192a2741183415543f6119f50a982/src/UnitTests/CustomValidations.cs#L42).

docs/Configuration.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,13 @@ var configuration = new MapperConfiguration(cfg => {});
215215
configuration.CompileMappings();
216216
```
217217

218-
For a few hundred mappings, this may take a couple of seconds.
218+
For a few hundred mappings, this may take a couple of seconds. If it's a lot more than that, you probably have some really big execution plans.
219+
220+
### Long compilation times
221+
222+
Compilation times increase with the size of the execution plan and that depends on the number of properties and their complexity. Ideally, you would fix your model so you have many small DTOs, each for a particular use case. But you can also decrease the size of the execution plan without changing your classes.
223+
224+
You can set `MapAtRuntime` per member or `MaxExecutionPlanDepth` globally (the default is one, set it to zero).
225+
226+
These will reduce the size of the execution plan by replacing the execution plan for a child object with a method call. The compilation will be faster, but the mapping itself might be slower. Search the repo for more details and use a profiler to better understand the effect.
227+
Avoiding `PreserveReferences` and `MaxDepth` also helps.

docs/Custom-type-converters.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,4 @@ public class TypeTypeConverter : ITypeConverter<string, Type>
8585

8686
In the first mapping, from string to Int32, we simply use the built-in Convert.ToInt32 function (supplied as a method group). The next two use custom ITypeConverter implementations.
8787

88-
The real power of custom type converters is that they are used any time AutoMapper finds the source/destination pairs on any mapped types. We can build a set of custom type converters, on top of which other mapping configurations use, without needing any extra configuration. In the above example, we never have to specify the string/int conversion again. Where as [Custom Value Resolvers](Custom-value-resolvers.html) have to be configured at a type member level, custom type converters are global in scope.
89-
90-
## System Type Converters
91-
92-
The .NET Framework also supports the concepts of type converters, through the [TypeConverter](http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx) class. AutoMapper supports these types of type converters, in configuration checking and mapping, without the need for any manual configuration. AutoMapper uses the [TypeDescriptor.GetConverter](http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.getconverter.aspx) method for determining if the source/destination type pair can be mapped.
88+
The real power of custom type converters is that they are used any time AutoMapper finds the source/destination pairs on any mapped types. We can build a set of custom type converters, on top of which other mapping configurations use, without needing any extra configuration. In the above example, we never have to specify the string/int conversion again. Where as [Custom Value Resolvers](Custom-value-resolvers.html) have to be configured at a type member level, custom type converters are global in scope.

docs/Dependency-injection.md

Lines changed: 3 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Dependency Injection
2+
13
## Examples
24

35
### ASP.NET Core
@@ -28,181 +30,8 @@ There is a third-party [NuGet package](https://www.nuget.org/packages/AutoMapper
2830

2931
Also, check [this blog](https://dotnetfalcon.com/autofac-support-for-automapper/).
3032

31-
### Ninject
32-
33-
For those using Ninject here is an example of a Ninject module for AutoMapper
34-
35-
```c#
36-
public class AutoMapperModule : NinjectModule
37-
{
38-
public override void Load()
39-
{
40-
Bind<IValueResolver<SourceEntity, DestModel, bool>>().To<MyResolver>();
41-
42-
var mapperConfiguration = CreateConfiguration();
43-
Bind<MapperConfiguration>().ToConstant(mapperConfiguration).InSingletonScope();
44-
45-
// This teaches Ninject how to create automapper instances say if for instance
46-
// MyResolver has a constructor with a parameter that needs to be injected
47-
Bind<IMapper>().ToMethod(ctx =>
48-
new Mapper(mapperConfiguration, type => ctx.Kernel.Get(type)));
49-
}
50-
51-
private MapperConfiguration CreateConfiguration()
52-
{
53-
var config = new MapperConfiguration(cfg =>
54-
{
55-
// Add all profiles in current assembly
56-
cfg.AddMaps(GetType().Assembly);
57-
});
58-
59-
return config;
60-
}
61-
}
62-
```
63-
64-
### Simple Injector
65-
66-
The workflow is as follows:
67-
68-
1) Register your types via MyRegistrar.Register
69-
2) The MapperProvider allows you to directly inject an instance of IMapper into your other classes
70-
3) SomeProfile resolves a value using PropertyThatDependsOnIocValueResolver
71-
4) PropertyThatDependsOnIocValueResolver has IService injected into it, which is then able to be used
72-
73-
The ValueResolver has access to IService because we register our container via MapperConfigurationExpression.ConstructServicesUsing
74-
75-
```c#
76-
public class MyRegistrar
77-
{
78-
public void Register(Container container)
79-
{
80-
// Injectable service
81-
container.RegisterSingleton<IService, SomeService>();
82-
83-
// Automapper
84-
container.RegisterSingleton(() => GetMapper(container));
85-
}
86-
87-
private AutoMapper.IMapper GetMapper(Container container)
88-
{
89-
var mp = container.GetInstance<MapperProvider>();
90-
return mp.GetMapper();
91-
}
92-
}
93-
94-
public class MapperProvider
95-
{
96-
private readonly Container _container;
97-
98-
public MapperProvider(Container container)
99-
{
100-
_container = container;
101-
}
102-
103-
public IMapper GetMapper()
104-
{
105-
var mce = new MapperConfigurationExpression();
106-
mce.ConstructServicesUsing(_container.GetInstance);
107-
108-
mce.AddMaps(typeof(SomeProfile).Assembly);
109-
110-
var mc = new MapperConfiguration(mce);
111-
mc.AssertConfigurationIsValid();
112-
113-
IMapper m = new Mapper(mc, t => _container.GetInstance(t));
114-
115-
return m;
116-
}
117-
}
118-
119-
public class SomeProfile : Profile
120-
{
121-
public SomeProfile()
122-
{
123-
var map = CreateMap<MySourceType, MyDestinationType>();
124-
map.ForMember(d => d.PropertyThatDependsOnIoc, opt => opt.MapFrom<PropertyThatDependsOnIocValueResolver>());
125-
}
126-
}
127-
128-
public class PropertyThatDependsOnIocValueResolver : IValueResolver<MySourceType, object, int>
129-
{
130-
private readonly IService _service;
131-
132-
public PropertyThatDependsOnIocValueResolver(IService service)
133-
{
134-
_service = service;
135-
}
33+
### [Other DI engines](https://github.com/AutoMapper/AutoMapper/wiki/DI-examples)
13634

137-
int IValueResolver<MySourceType, object, int>.Resolve(MySourceType source, object destination, int destMember, ResolutionContext context)
138-
{
139-
return _service.MyMethod(source);
140-
}
141-
}
142-
```
143-
144-
### Castle Windsor
145-
146-
For those using Castle Windsor here is an example of an installer for AutoMapper
147-
148-
```c#
149-
public class AutoMapperInstaller : IWindsorInstaller
150-
{
151-
public void Install(IWindsorContainer container, IConfigurationStore store)
152-
{
153-
// Register all mapper profiles
154-
container.Register(
155-
Classes.FromAssemblyInThisApplication(GetType().Assembly)
156-
.BasedOn<Profile>().WithServiceBase());
157-
158-
// Register IConfigurationProvider with all registered profiles
159-
container.Register(Component.For<IConfigurationProvider>().UsingFactoryMethod(kernel =>
160-
{
161-
return new MapperConfiguration(configuration =>
162-
{
163-
kernel.ResolveAll<Profile>().ToList().ForEach(configuration.AddProfile);
164-
});
165-
}).LifestyleSingleton());
166-
167-
// Register IMapper with registered IConfigurationProvider
168-
container.Register(
169-
Component.For<IMapper>().UsingFactoryMethod(kernel =>
170-
new Mapper(kernel.Resolve<IConfigurationProvider>(), kernel.Resolve)));
171-
}
172-
}
173-
```
174-
175-
### Catel.IoC
176-
177-
For those using Catel.IoC here is how you register AutoMapper. First define the configuration using [profiles](Configuration.html#profile-instances). And then you let AutoMapper know in what assemblies those profiles are defined by registering AutoMapper in the ServiceLocator at startup:
178-
```c#
179-
ServiceLocator.Default.RegisterInstance(typeof(IMapper), new Mapper(CreateConfiguration()));
180-
```
181-
182-
Configuration Creation Method:
183-
```c#
184-
public static MapperConfiguration CreateConfiguration()
185-
{
186-
var config = new MapperConfiguration(cfg =>
187-
{
188-
// Add all profiles in current assembly
189-
cfg.AddMaps(GetType().Assembly);
190-
});
191-
192-
return config;
193-
}
194-
```
195-
196-
Now you can inject AutoMapper at runtime into your services/controllers:
197-
```c#
198-
public class EmployeesController {
199-
private readonly IMapper _mapper;
200-
201-
public EmployeesController(IMapper mapper) => _mapper = mapper;
202-
203-
// use _mapper.Map or _mapper.ProjectTo
204-
}
205-
```
20635
## Low level API-s
20736

20837
AutoMapper supports the ability to construct [Custom Value Resolvers](Custom-value-resolvers.html), [Custom Type Converters](Custom-type-converters.html), and [Value Converters](Value-converters.html) using static service location:

0 commit comments

Comments
 (0)