Skip to content

Commit 1970f0f

Browse files
Fix models in multiple EDMs with same API version; Fixes #996
1 parent 2487953 commit 1970f0f

File tree

4 files changed

+44
-15
lines changed

4 files changed

+44
-15
lines changed

src/Common/src/Common.OData.ApiExplorer/OData/ClassSignature.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ internal sealed class ClassSignature : IEquatable<ClassSignature>
1212
private static readonly ConstructorInfo newOriginalType = typeof( OriginalTypeAttribute ).GetConstructors()[0];
1313
private int? hashCode;
1414

15-
internal ClassSignature( Type originalType, IEnumerable<ClassProperty> properties, ApiVersion apiVersion )
15+
internal ClassSignature( string name, Type originalType, IEnumerable<ClassProperty> properties, ApiVersion apiVersion )
1616
{
1717
var attributeBuilders = new List<CustomAttributeBuilder>()
1818
{
@@ -21,7 +21,7 @@ internal ClassSignature( Type originalType, IEnumerable<ClassProperty> propertie
2121

2222
attributeBuilders.AddRange( originalType.DeclaredAttributes() );
2323

24-
Name = originalType.FullName!;
24+
Name = name;
2525
Attributes = attributeBuilders.ToArray();
2626
Properties = properties.ToArray();
2727
ApiVersion = apiVersion;

src/Common/src/Common.OData.ApiExplorer/OData/DefaultModelTypeBuilder.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ public sealed class DefaultModelTypeBuilder : IModelTypeBuilder
4141
private readonly bool adHoc;
4242
private readonly bool excludeAdHocModels;
4343
private DefaultModelTypeBuilder? adHocBuilder;
44-
private ConcurrentDictionary<ApiVersion, ModuleBuilder>? modules;
45-
private ConcurrentDictionary<ApiVersion, IDictionary<EdmTypeKey, Type>>? generatedEdmTypesPerVersion;
46-
private ConcurrentDictionary<ApiVersion, ConcurrentDictionary<EdmTypeKey, Type>>? generatedActionParamsPerVersion;
44+
private ConcurrentDictionary<EdmModelKey, ModuleBuilder>? modules;
45+
private ConcurrentDictionary<EdmModelKey, IDictionary<EdmTypeKey, Type>>? generatedEdmTypesPerVersion;
46+
private ConcurrentDictionary<EdmModelKey, ConcurrentDictionary<EdmTypeKey, Type>>? generatedActionParamsPerVersion;
4747

4848
private DefaultModelTypeBuilder( bool excludeAdHocModels, bool adHoc )
4949
{
@@ -96,7 +96,7 @@ public Type NewStructuredType( IEdmModel model, IEdmStructuredType structuredTyp
9696

9797
generatedEdmTypesPerVersion ??= new();
9898

99-
var edmTypes = generatedEdmTypesPerVersion.GetOrAdd( apiVersion, key => GenerateTypesForEdmModel( model, key ) );
99+
var edmTypes = generatedEdmTypesPerVersion.GetOrAdd( new( model, apiVersion ), key => GenerateTypesForEdmModel( model, key.ApiVersion ) );
100100

101101
return edmTypes[new( structuredType, apiVersion )];
102102
}
@@ -132,15 +132,15 @@ public Type NewActionParameters( IEdmModel model, IEdmAction action, string cont
132132

133133
generatedActionParamsPerVersion ??= new();
134134

135-
var paramTypes = generatedActionParamsPerVersion.GetOrAdd( apiVersion, _ => new() );
135+
var paramTypes = generatedActionParamsPerVersion.GetOrAdd( new( model, apiVersion ), _ => new() );
136136
var fullTypeName = $"{controllerName}.{action.Namespace}.{controllerName}{action.Name}Parameters";
137137
var key = new EdmTypeKey( fullTypeName, apiVersion );
138138
var type = paramTypes.GetOrAdd( key, _ =>
139139
{
140140
var context = new TypeSubstitutionContext( model, this, apiVersion );
141141
var properties = action.Parameters.Where( p => p.Name != "bindingParameter" ).Select( p => new ClassProperty( p, context ) );
142142
var signature = new ClassSignature( fullTypeName, properties, apiVersion );
143-
var moduleBuilder = ( modules ??= new() ).GetOrAdd( apiVersion, CreateModuleForApiVersion );
143+
var moduleBuilder = ( modules ??= new() ).GetOrAdd( new( model, apiVersion ), CreateModuleForApiVersion );
144144

145145
return CreateTypeFromSignature( moduleBuilder, signature );
146146
} );
@@ -150,7 +150,7 @@ public Type NewActionParameters( IEdmModel model, IEdmAction action, string cont
150150

151151
private IDictionary<EdmTypeKey, Type> GenerateTypesForEdmModel( IEdmModel model, ApiVersion apiVersion )
152152
{
153-
ModuleBuilder NewModuleBuilder() => ( modules ??= new() ).GetOrAdd( apiVersion, CreateModuleForApiVersion );
153+
ModuleBuilder NewModuleBuilder() => ( modules ??= new() ).GetOrAdd( new( model, apiVersion ), CreateModuleForApiVersion );
154154

155155
var context = new BuilderContext( model, apiVersion, NewModuleBuilder );
156156

@@ -336,7 +336,7 @@ private static Type ResolveType(
336336
return type;
337337
}
338338

339-
var signature = new ClassSignature( clrType, properties, apiVersion );
339+
var signature = new ClassSignature( typeKey.FullName, clrType, properties, apiVersion );
340340

341341
if ( hasUnfinishedTypes )
342342
{
@@ -518,9 +518,9 @@ private static AssemblyName NewAssemblyName( ApiVersion apiVersion, bool adHoc )
518518
}
519519

520520
[MethodImpl( MethodImplOptions.AggressiveInlining )]
521-
private ModuleBuilder CreateModuleForApiVersion( ApiVersion apiVersion )
521+
private ModuleBuilder CreateModuleForApiVersion( EdmModelKey key )
522522
{
523-
var assemblyName = NewAssemblyName( apiVersion, adHoc );
523+
var assemblyName = NewAssemblyName( key.ApiVersion, adHoc );
524524
#if NETFRAMEWORK
525525
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName, Run );
526526
#else
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.OData;
4+
5+
using Microsoft.OData.Edm;
6+
7+
internal readonly struct EdmModelKey : IEquatable<EdmModelKey>
8+
{
9+
private readonly int hashCode;
10+
11+
public readonly IEdmModel EdmModel;
12+
public readonly ApiVersion ApiVersion;
13+
14+
internal EdmModelKey( IEdmModel model, ApiVersion apiVersion ) =>
15+
hashCode = HashCode.Combine( ( EdmModel = model ).GetHashCode(), ApiVersion = apiVersion );
16+
17+
public static bool operator ==( EdmModelKey obj, EdmModelKey other ) => obj.Equals( other );
18+
19+
public static bool operator !=( EdmModelKey obj, EdmModelKey other ) => !obj.Equals( other );
20+
21+
public override int GetHashCode() => hashCode;
22+
23+
public override bool Equals( object? obj ) => obj is EdmModelKey other && Equals( other );
24+
25+
public bool Equals( EdmModelKey other ) => hashCode == other.hashCode;
26+
}

src/Common/src/Common.OData.ApiExplorer/OData/EdmTypeKey.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ namespace Asp.Versioning.OData;
88
{
99
private readonly int hashCode;
1010

11+
public readonly string FullName;
12+
public readonly ApiVersion ApiVersion;
13+
1114
internal EdmTypeKey( IEdmStructuredType type, ApiVersion apiVersion ) =>
12-
hashCode = HashCode.Combine( type.FullTypeName(), apiVersion );
15+
hashCode = HashCode.Combine( FullName = type.FullTypeName(), ApiVersion = apiVersion );
1316

1417
internal EdmTypeKey( IEdmTypeReference type, ApiVersion apiVersion ) =>
15-
hashCode = HashCode.Combine( type.FullName(), apiVersion );
18+
hashCode = HashCode.Combine( FullName = type.FullName(), ApiVersion = apiVersion );
1619

1720
internal EdmTypeKey( string fullTypeName, ApiVersion apiVersion ) =>
18-
hashCode = HashCode.Combine( fullTypeName, apiVersion );
21+
hashCode = HashCode.Combine( FullName = fullTypeName, ApiVersion = apiVersion );
1922

2023
public static bool operator ==( EdmTypeKey obj, EdmTypeKey other ) => obj.Equals( other );
2124

0 commit comments

Comments
 (0)