@@ -15,6 +15,25 @@ public static class ServiceCollectionExtensions
1515
1616 private static readonly Action < IMapperConfigurationExpression > DefaultConfig = cfg => { } ;
1717#if DEPENDENCY_MODEL
18+
19+ private static HashSet < string > ReferenceAssemblies { get ; } = new HashSet < string > ( StringComparer . OrdinalIgnoreCase )
20+ {
21+ //"Microsoft.AspNetCore.Mvc",
22+ //"Microsoft.AspNetCore.Mvc.Abstractions",
23+ //"Microsoft.AspNetCore.Mvc.ApiExplorer",
24+ //"Microsoft.AspNetCore.Mvc.Core",
25+ //"Microsoft.AspNetCore.Mvc.Cors",
26+ //"Microsoft.AspNetCore.Mvc.DataAnnotations",
27+ //"Microsoft.AspNetCore.Mvc.Formatters.Json",
28+ //"Microsoft.AspNetCore.Mvc.Formatters.Xml",
29+ //"Microsoft.AspNetCore.Mvc.Localization",
30+ //"Microsoft.AspNetCore.Mvc.Razor",
31+ //"Microsoft.AspNetCore.Mvc.Razor.Host",
32+ //"Microsoft.AspNetCore.Mvc.TagHelpers",
33+ //"Microsoft.AspNetCore.Mvc.ViewFeatures",
34+ "AutoMapper"
35+ } ;
36+
1837 public static IServiceCollection AddAutoMapper ( this IServiceCollection services )
1938 {
2039 return services . AddAutoMapper ( null , DependencyContext . Default ) ;
@@ -27,15 +46,123 @@ public static IServiceCollection AddAutoMapper(this IServiceCollection services,
2746
2847 public static IServiceCollection AddAutoMapper ( this IServiceCollection services , Action < IMapperConfigurationExpression > additionalInitAction , DependencyContext dependencyContext )
2948 {
30- return services . AddAutoMapper ( additionalInitAction ,
31- dependencyContext . RuntimeLibraries
32- // Only load assemblies that reference AutoMapper
33- . Where ( lib =>
34- lib . Type . Equals ( "msbuildproject" , StringComparison . OrdinalIgnoreCase ) ||
35- lib . Dependencies . Any ( d => d . Name . StartsWith ( AutoMapperAssembly . GetName ( ) . Name , StringComparison . OrdinalIgnoreCase ) ) )
36- . SelectMany ( lib => lib . GetDefaultAssemblyNames ( dependencyContext )
37- . Select ( Assembly . Load ) ) ) ;
49+ return services . AddAutoMapper ( additionalInitAction , GetCandidateAssemblies ( dependencyContext ) ) ;
50+ }
51+
52+ private static IEnumerable < Assembly > GetCandidateAssemblies ( DependencyContext dependencyContext )
53+ {
54+ return GetCandidateLibraries ( dependencyContext )
55+ . SelectMany ( library => library . GetDefaultAssemblyNames ( dependencyContext ) )
56+ . Select ( Assembly . Load ) ;
57+ }
58+
59+ private static IEnumerable < RuntimeLibrary > GetCandidateLibraries ( DependencyContext dependencyContext )
60+ {
61+ if ( ReferenceAssemblies == null )
62+ {
63+ return Enumerable . Empty < RuntimeLibrary > ( ) ;
64+ }
65+
66+ var candidatesResolver = new CandidateResolver ( dependencyContext . RuntimeLibraries , ReferenceAssemblies ) ;
67+ return candidatesResolver . GetCandidates ( ) ;
3868 }
69+
70+ private class CandidateResolver
71+ {
72+ private readonly IDictionary < string , Dependency > _dependencies ;
73+
74+ public CandidateResolver ( IReadOnlyList < RuntimeLibrary > dependencies , ISet < string > referenceAssemblies )
75+ {
76+ var dependenciesWithNoDuplicates = new Dictionary < string , Dependency > ( StringComparer . OrdinalIgnoreCase ) ;
77+ foreach ( var dependency in dependencies )
78+ {
79+ if ( dependenciesWithNoDuplicates . ContainsKey ( dependency . Name ) )
80+ {
81+ throw new InvalidOperationException (
82+ $ "A duplicate entry for library reference { dependency . Name } was found. Please check that all package references in all projects use the same casing for the same package references.") ;
83+ }
84+ dependenciesWithNoDuplicates . Add ( dependency . Name , CreateDependency ( dependency , referenceAssemblies ) ) ;
85+ }
86+
87+ _dependencies = dependenciesWithNoDuplicates ;
88+ }
89+
90+ private Dependency CreateDependency ( RuntimeLibrary library , ISet < string > referenceAssemblies )
91+ {
92+ var classification = DependencyClassification . Unknown ;
93+ if ( referenceAssemblies . Contains ( library . Name ) )
94+ {
95+ classification = DependencyClassification . AutoMapperReference ;
96+ }
97+
98+ return new Dependency ( library , classification ) ;
99+ }
100+
101+ private DependencyClassification ComputeClassification ( string dependency )
102+ {
103+ var candidateEntry = _dependencies [ dependency ] ;
104+ if ( candidateEntry . Classification != DependencyClassification . Unknown )
105+ {
106+ return candidateEntry . Classification ;
107+ }
108+ else
109+ {
110+ var classification = DependencyClassification . NotCandidate ;
111+ foreach ( var candidateDependency in candidateEntry . Library . Dependencies )
112+ {
113+ var dependencyClassification = ComputeClassification ( candidateDependency . Name ) ;
114+ if ( dependencyClassification == DependencyClassification . Candidate ||
115+ dependencyClassification == DependencyClassification . AutoMapperReference )
116+ {
117+ classification = DependencyClassification . Candidate ;
118+ break ;
119+ }
120+ }
121+
122+ candidateEntry . Classification = classification ;
123+
124+ return classification ;
125+ }
126+ }
127+
128+ public IEnumerable < RuntimeLibrary > GetCandidates ( )
129+ {
130+ foreach ( var dependency in _dependencies )
131+ {
132+ if ( ComputeClassification ( dependency . Key ) == DependencyClassification . Candidate )
133+ {
134+ yield return dependency . Value . Library ;
135+ }
136+ }
137+ }
138+
139+ private class Dependency
140+ {
141+ public Dependency ( RuntimeLibrary library , DependencyClassification classification )
142+ {
143+ Library = library ;
144+ Classification = classification ;
145+ }
146+
147+ public RuntimeLibrary Library { get ; }
148+
149+ public DependencyClassification Classification { get ; set ; }
150+
151+ public override string ToString ( )
152+ {
153+ return $ "Library: { Library . Name } , Classification: { Classification } ";
154+ }
155+ }
156+
157+ private enum DependencyClassification
158+ {
159+ Unknown = 0 ,
160+ Candidate = 1 ,
161+ NotCandidate = 2 ,
162+ AutoMapperReference = 3
163+ }
164+ }
165+
39166#endif
40167
41168 public static IServiceCollection AddAutoMapper ( this IServiceCollection services , params Assembly [ ] assemblies )
0 commit comments