From 8b5bfe35bcc6f54f9d20e5f0613fa4e904f292e7 Mon Sep 17 00:00:00 2001 From: Blaise Taylor Date: Sat, 31 May 2025 10:21:22 -0400 Subject: [PATCH] Fixes Issue #242. Exception expanding dictionaries in complex types. --- .../TypeExtensions.cs | 8 ++- .../AirVinylModel/VinylRecordModel.cs | 54 ++++++++++++++++++- .../ExpansionTests.cs | 16 ++++++ .../Mappings/AirVinylMappings.cs | 3 ++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/AutoMapper.AspNetCore.OData.EFCore/TypeExtensions.cs b/AutoMapper.AspNetCore.OData.EFCore/TypeExtensions.cs index 6932a42..1a7af70 100644 --- a/AutoMapper.AspNetCore.OData.EFCore/TypeExtensions.cs +++ b/AutoMapper.AspNetCore.OData.EFCore/TypeExtensions.cs @@ -117,12 +117,18 @@ public static Type GetUnderlyingElementType(this Type type) if (genericTypeDefinition == typeof(IGrouping<,>)) return genericArguments[1]; - else if (typeof(IDictionary<,>).IsAssignableFrom(genericTypeDefinition)) + else if (IsGenericDictionaryType()) return typeof(KeyValuePair<,>).MakeGenericType(genericArguments[0], genericArguments[1]); else if (genericArguments.Length == 1) return genericArguments[0]; else throw new ArgumentException(nameof(type)); + + bool IsGenericDictionaryType() + { + return (typeof(IDictionary<,>).IsAssignableFrom(genericTypeDefinition)) + || (type.GetInterface(typeof(System.Collections.IDictionary).FullName ?? "") != null && genericArguments.Length == 2); + } } public static Type GetUnderlyingElementType(this Expression expression) diff --git a/AutoMapper.OData.EFCore.Tests/AirVinylModel/VinylRecordModel.cs b/AutoMapper.OData.EFCore.Tests/AirVinylModel/VinylRecordModel.cs index 93e0d15..254a829 100644 --- a/AutoMapper.OData.EFCore.Tests/AirVinylModel/VinylRecordModel.cs +++ b/AutoMapper.OData.EFCore.Tests/AirVinylModel/VinylRecordModel.cs @@ -49,6 +49,58 @@ public IDictionary Links { return _links; } - } + } + + private Dictionary _moreLinks; + public Dictionary MoreLinks + { + get + { + if (_moreLinks is null) + { + _moreLinks = new Dictionary() + { + { "buyingLink", new VinylLinkModel { Href = $"http://test/buy/{VinylRecordId}" } }, + { "reviewLink", new VinylLinkModel { Href = $"http://test/review/{VinylRecordId}" } } + }; + } + + return _moreLinks; + } + } + + private SortedDictionary _extraLinks; + public SortedDictionary ExtraLinks + { + get + { + if (_extraLinks is null) + { + _extraLinks = new SortedDictionary() + { + { "buyingLink", new VinylLinkModel { Href = $"http://test/buy/{VinylRecordId}" } }, + { "reviewLink", new VinylLinkModel { Href = $"http://test/review/{VinylRecordId}" } } + }; + } + + return _extraLinks; + } + } + + private System.Collections.Concurrent.ConcurrentDictionary _additionalLinks; + public System.Collections.Concurrent.ConcurrentDictionary AdditionalLinks + { + get + { + if (_additionalLinks is null) + { + _additionalLinks = new System.Collections.Concurrent.ConcurrentDictionary(); + _additionalLinks.TryAdd("buyingLink", new VinylLinkModel { Href = $"http://test/buy/{VinylRecordId}" }); + _additionalLinks.TryAdd("reviewLink", new VinylLinkModel { Href = $"http://test/review/{VinylRecordId}" }); + } + + return _additionalLinks; + } + } } } diff --git a/AutoMapper.OData.EFCore.Tests/ExpansionTests.cs b/AutoMapper.OData.EFCore.Tests/ExpansionTests.cs index 01a30b9..7e9f043 100644 --- a/AutoMapper.OData.EFCore.Tests/ExpansionTests.cs +++ b/AutoMapper.OData.EFCore.Tests/ExpansionTests.cs @@ -65,6 +65,22 @@ void Test(ICollection collection) } } + [Fact] + public async Task ExpandingComplexTypesSupportsAllGenericDictionaries() + { + string query = "/vinylrecordmodel"; + Test(await GetAsync(query)); + + void Test(ICollection collection) + { + Assert.True(collection.Count > 0); + Assert.Contains(collection, vinyl => vinyl.Links.Count != 0); + Assert.Contains(collection, vinyl => vinyl.MoreLinks.Count != 0); + Assert.Contains(collection, vinyl => vinyl.ExtraLinks.Count != 0); + Assert.Contains(collection, vinyl => vinyl.AdditionalLinks.Count != 0); + } + } + [Fact] public async Task GetRecordStoresExpandsComplexTypesByDefault() { diff --git a/AutoMapper.OData.EFCore.Tests/Mappings/AirVinylMappings.cs b/AutoMapper.OData.EFCore.Tests/Mappings/AirVinylMappings.cs index 748dc64..f553a0c 100644 --- a/AutoMapper.OData.EFCore.Tests/Mappings/AirVinylMappings.cs +++ b/AutoMapper.OData.EFCore.Tests/Mappings/AirVinylMappings.cs @@ -31,6 +31,9 @@ public AirVinylMappings() .ForAllMembers(o => o.ExplicitExpansion()); CreateMap() .ForMember(dest => dest.Links, o => o.Ignore()) + .ForMember(dest => dest.MoreLinks, o => o.Ignore()) + .ForMember(dest => dest.ExtraLinks, o => o.Ignore()) + .ForMember(dest => dest.AdditionalLinks, o => o.Ignore()) .ForAllMembers(o => o.ExplicitExpansion()); } }