Skip to content

Commit b841a10

Browse files
Chris Martinezcommonsensesoftware
authored andcommitted
Refactor to build attribute route info after route registration
1 parent 529e590 commit b841a10

File tree

37 files changed

+944
-210
lines changed

37 files changed

+944
-210
lines changed

src/Common.OData.ApiExplorer/AspNet.OData/ClassProperty.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ internal ClassProperty( PropertyInfo clrProperty )
2929
Attributes = AttributesFromProperty( clrProperty );
3030
}
3131

32-
internal ClassProperty( IAssembliesResolver assemblyResolver, IEdmOperationParameter parameter )
32+
internal ClassProperty( IEnumerable<Assembly> assemblies, IEdmOperationParameter parameter )
3333
{
34-
Contract.Requires( assemblyResolver != null );
34+
Contract.Requires( assemblies != null );
3535
Contract.Requires( parameter != null );
3636

3737
Name = parameter.Name;
38-
Type = parameter.Type.Definition.GetClrType( assemblyResolver );
38+
Type = parameter.Type.Definition.GetClrType( assemblies );
3939
Attributes = AttributesFromOperationParameter( parameter );
4040
}
4141

src/Common.OData.ApiExplorer/AspNet.OData/ModelTypeBuilder.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,11 @@
2424

2525
sealed class ModelTypeBuilder
2626
{
27-
readonly IAssembliesResolver assembliesResolver;
27+
readonly IEnumerable<Assembly> assemblies;
2828
readonly ConcurrentDictionary<ApiVersion, ModuleBuilder> modules = new ConcurrentDictionary<ApiVersion, ModuleBuilder>();
2929
readonly ConcurrentDictionary<ClassSignature, Type> generatedTypes = new ConcurrentDictionary<ClassSignature, Type>();
3030

31-
internal ModelTypeBuilder( IAssembliesResolver assembliesResolver )
32-
{
33-
Contract.Requires( assembliesResolver != null );
34-
this.assembliesResolver = assembliesResolver;
35-
}
31+
internal ModelTypeBuilder( IEnumerable<Assembly> assemblies ) => this.assemblies = assemblies;
3632

3733
internal Type NewStructuredType( IEdmStructuredType structuredType, Type clrType, ApiVersion apiVersion )
3834
{
@@ -67,7 +63,7 @@ internal Type NewActionParameters( IEdmAction action, ApiVersion apiVersion )
6763
Contract.Ensures( Contract.Result<Type>() != null );
6864

6965
var name = action.FullName() + "Parameters";
70-
var properties = action.Parameters.Where( p => p.Name != "bindingParameter" ).Select( p => new ClassProperty( assembliesResolver, p ) );
66+
var properties = action.Parameters.Where( p => p.Name != "bindingParameter" ).Select( p => new ClassProperty( assemblies, p ) );
7167
var signature = new ClassSignature( name, properties, apiVersion );
7268

7369
return generatedTypes.GetOrAdd( signature, CreateFromSignature );

src/Common.OData.ApiExplorer/AspNet.OData/Routing/ODataRouteBuilder.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#else
2727
using static Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource;
2828
#endif
29+
#if !API_EXPLORER
30+
using ApiParameterDescription = Microsoft.AspNetCore.Mvc.Abstractions.ParameterDescriptor;
31+
#endif
2932

3033
sealed partial class ODataRouteBuilder
3134
{
@@ -138,7 +141,11 @@ void AppendEntitySetOrOperation( IList<string> segments )
138141
AppendEntityKeysFromConvention( builder );
139142
segments.Add( builder.ToString() );
140143
builder.Clear();
144+
#if API_EXPLORER
141145
builder.Append( Context.Options.UseQualifiedOperationNames ? Context.Operation.ShortQualifiedName() : Context.Operation.Name );
146+
#else
147+
builder.Append( Context.Operation.ShortQualifiedName() );
148+
#endif
142149
AppendParametersFromConvention( builder, Context.Operation );
143150
break;
144151
case UnboundOperation:
@@ -217,8 +224,10 @@ void AppendParametersFromConvention( StringBuilder builder, IEdmOperation operat
217224
var name = parameter.Name;
218225
#if WEBAPI
219226
var routeParameterName = actionParameters[name].ParameterDescriptor.ParameterName;
220-
#else
227+
#elif API_EXPLORER
221228
var routeParameterName = actionParameters[name].ParameterDescriptor.Name;
229+
#else
230+
var routeParameterName = actionParameters[name].Name;
222231
#endif
223232

224233
builder.Append( '(' );
@@ -232,8 +241,10 @@ void AppendParametersFromConvention( StringBuilder builder, IEdmOperation operat
232241
name = parameter.Name;
233242
#if WEBAPI
234243
routeParameterName = actionParameters[name].ParameterDescriptor.ParameterName;
235-
#else
244+
#elif API_EXPLORER
236245
routeParameterName = actionParameters[name].ParameterDescriptor.Name;
246+
#else
247+
routeParameterName = actionParameters[name].Name;
237248
#endif
238249
builder.Append( ',' );
239250
builder.Append( name );
@@ -279,7 +290,7 @@ void ExpandParameterTemplate( StringBuilder template, IEdmTypeReference typeRefe
279290
return;
280291
}
281292

282-
var type = typeDef.GetClrType( Context.AssembliesResolver );
293+
var type = typeDef.GetClrType( Context.Assemblies );
283294

284295
if ( quotedTypes.TryGetValue( type, out var prefix ) )
285296
{
@@ -344,14 +355,20 @@ IList<ApiParameterDescription> GetQueryParameters( IList<ApiParameterDescription
344355
{
345356
#if WEBAPI
346357
if ( parameter.Source != FromUri )
347-
#else
358+
#elif API_EXPLORER
348359
if ( parameter.Source != Query )
360+
#else
361+
if ( parameter.BindingInfo.BindingSource != Query )
349362
#endif
350363
{
351364
continue;
352365
}
353366

367+
#if API_EXPLORER
354368
var parameterType = parameter.ParameterDescriptor?.ParameterType;
369+
#else
370+
var parameterType = parameter.ParameterType;
371+
#endif
355372

356373
if ( parameterType == null || IsBuiltInParameter( parameterType ) )
357374
{

src/Common.OData.ApiExplorer/AspNet.OData/Routing/ODataRouteBuilderContext.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
#if !WEBAPI
44
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.AspNetCore.Mvc.Abstractions;
56
using Microsoft.AspNetCore.Mvc.ApiExplorer;
67
using Microsoft.AspNetCore.Mvc.Controllers;
78
#endif
@@ -15,6 +16,7 @@
1516
#endif
1617
using System;
1718
using System.Collections.Generic;
19+
using System.Reflection;
1820
#if WEBAPI
1921
using System.Web.Http.Description;
2022
using System.Web.Http.Dispatcher;
@@ -28,7 +30,15 @@ sealed partial class ODataRouteBuilderContext
2830

2931
internal ApiVersion ApiVersion { get; }
3032

31-
internal IAssembliesResolver AssembliesResolver { get; }
33+
#if API_EXPLORER
34+
internal ODataApiExplorerOptions Options { get; }
35+
36+
internal IList<ApiParameterDescription> ParameterDescriptions { get; }
37+
#else
38+
internal IList<ParameterDescriptor> ParameterDescriptions => ActionDescriptor.Parameters;
39+
#endif
40+
41+
internal IEnumerable<Assembly> Assemblies { get; }
3242

3343
internal IEdmModel EdmModel { get; }
3444

@@ -38,16 +48,12 @@ sealed partial class ODataRouteBuilderContext
3848

3949
internal ControllerActionDescriptor ActionDescriptor { get; }
4050

41-
internal IList<ApiParameterDescription> ParameterDescriptions { get; }
42-
4351
internal IEdmEntitySet EntitySet { get; }
4452

4553
internal IEdmOperation Operation { get; }
4654

4755
internal ODataRouteActionType ActionType { get; }
4856

49-
internal ODataApiExplorerOptions Options { get; }
50-
5157
internal ODataUrlKeyDelimiter UrlKeyDelimiter { get; }
5258

5359
internal bool IsRouteExcluded { get; }

src/Common.OData.ApiExplorer/AspNet.OData/TypeExtensions.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ static partial class TypeExtensions
2828
static readonly Type ActionResultType = typeof( IActionResult );
2929
static readonly Type HttpResponseType = typeof( HttpResponseMessage );
3030
static readonly Type IEnumerableOfT = typeof( IEnumerable<> );
31-
static readonly Type ODataPath = typeof( ODataPath );
32-
static readonly Type ODataActionParameters = typeof( ODataActionParameters );
3331

34-
internal static bool IsODataPath( this Type type ) => ODataPath.IsAssignableFrom( type );
35-
36-
internal static bool IsODataActionParameters( this Type type ) => ODataActionParameters.IsAssignableFrom( type );
32+
#if WEBAPI
33+
internal static Type SubstituteIfNecessary( this Type type, IServiceProvider serviceProvider, IAssembliesResolver assembliesResolver, ModelTypeBuilder modelTypeBuilder ) =>
34+
type.SubstituteIfNecessary( serviceProvider, assembliesResolver.GetAssemblies(), modelTypeBuilder );
35+
#endif
3736

38-
internal static Type SubstituteIfNecessary( this Type type, IServiceProvider serviceProvider, IAssembliesResolver assembliesResolver, ModelTypeBuilder modelTypeBuilder )
37+
internal static Type SubstituteIfNecessary( this Type type, IServiceProvider serviceProvider, IEnumerable<Assembly> assemblies, ModelTypeBuilder modelTypeBuilder )
3938
{
4039
Contract.Requires( serviceProvider != null );
41-
Contract.Requires( assembliesResolver != null );
40+
Contract.Requires( assemblies != null );
4241
Contract.Requires( modelTypeBuilder != null );
4342
Contract.Ensures( Contract.Result<Type>() != null );
4443

@@ -51,7 +50,7 @@ internal static Type SubstituteIfNecessary( this Type type, IServiceProvider ser
5150

5251
var innerType = result.InnerType;
5352
var model = serviceProvider.GetRequiredService<IEdmModel>();
54-
var structuredType = innerType.GetStructuredType( model, assembliesResolver );
53+
var structuredType = innerType.GetStructuredType( model, assemblies );
5554

5655
if ( structuredType == null )
5756
{
@@ -128,14 +127,14 @@ static bool IsEnumerable( this Type type )
128127
return typeDef.Equals( IEnumerableOfT ) || typeDef.GetInterfaces().Any( i => i.IsGenericType && i.GetGenericTypeDefinition().Equals( IEnumerableOfT ) );
129128
}
130129

131-
static IEdmStructuredType GetStructuredType( this Type type, IEdmModel model, IAssembliesResolver assembliesResolver )
130+
static IEdmStructuredType GetStructuredType( this Type type, IEdmModel model, IEnumerable<Assembly> assemblies )
132131
{
133132
Contract.Requires( type != null );
134133
Contract.Requires( model != null );
135-
Contract.Requires( assembliesResolver != null );
134+
Contract.Requires( assemblies != null );
136135

137136
var structuredTypes = model.SchemaElements.OfType<IEdmStructuredType>();
138-
var structuredType = structuredTypes.FirstOrDefault( t => t.GetClrType( assembliesResolver ).Equals( type ) );
137+
var structuredType = structuredTypes.FirstOrDefault( t => t.GetClrType( assemblies ).Equals( type ) );
139138

140139
return structuredType;
141140
}

src/Common.OData.ApiExplorer/OData.Edm/EdmExtensions.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace Microsoft.OData.Edm
22
{
3+
using Microsoft.AspNet.OData;
34
#if !WEBAPI
45
using Microsoft.AspNetCore.Mvc.ApiExplorer;
56
#endif
@@ -16,10 +17,15 @@
1617

1718
static class EdmExtensions
1819
{
19-
internal static Type GetClrType( this IEdmType edmType, IAssembliesResolver assembliesResolver )
20+
#if WEBAPI
21+
internal static Type GetClrType( this IEdmType edmType, IAssembliesResolver assembliesResolver ) =>
22+
edmType.GetClrType( assembliesResolver.GetAssemblies() );
23+
#endif
24+
25+
internal static Type GetClrType( this IEdmType edmType, IEnumerable<Assembly> assemblies )
2026
{
2127
Contract.Requires( edmType != null );
22-
Contract.Requires( assembliesResolver != null );
28+
Contract.Requires( assemblies != null );
2329

2430
if ( !( edmType is IEdmSchemaType schemaType ) )
2531
{
@@ -34,7 +40,7 @@ internal static Type GetClrType( this IEdmType edmType, IAssembliesResolver asse
3440
return type;
3541
}
3642

37-
using ( var matchingTypes = GetMatchingTypes( typeName, assembliesResolver ).GetEnumerator() )
43+
using ( var matchingTypes = GetMatchingTypes( typeName, assemblies ).GetEnumerator() )
3844
{
3945
if ( matchingTypes.MoveNext() )
4046
{
@@ -101,13 +107,12 @@ static string MangleClrTypeName( this Type type )
101107
return Format( InvariantCulture, "{0}Of{1}", typeName, typeArgNames );
102108
}
103109

104-
static IEnumerable<Type> GetMatchingTypes( string edmFullName, IAssembliesResolver assembliesResolver ) =>
105-
assembliesResolver.LoadedTypes().Where( t => t.IsPublic && t.EdmFullName() == edmFullName );
110+
static IEnumerable<Type> GetMatchingTypes( string edmFullName, IEnumerable<Assembly> assemblies ) =>
111+
assemblies.LoadedTypes().Where( t => t.IsPublic && t.EdmFullName() == edmFullName );
106112

107-
static IEnumerable<Type> LoadedTypes( this IAssembliesResolver assembliesResolver )
113+
static IEnumerable<Type> LoadedTypes( this IEnumerable<Assembly> assemblies )
108114
{
109115
var loadedTypes = new List<Type>();
110-
var assemblies = assembliesResolver.GetAssemblies();
111116

112117
foreach ( var assembly in assemblies.Where( a => a?.IsDynamic == false ) )
113118
{

src/Common.OData/TypeExtensions.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,39 @@
11
namespace Microsoft.AspNet.OData
22
{
33
using Microsoft.AspNet.OData.Query;
4+
using Microsoft.AspNet.OData.Routing;
45
using System;
56
using System.Reflection;
67

78
static partial class TypeExtensions
89
{
910
static readonly TypeInfo ODataController = typeof( ODataController ).GetTypeInfo();
1011
static readonly TypeInfo MetadataController = typeof( MetadataController ).GetTypeInfo();
12+
static readonly Type Delta = typeof( IDelta );
13+
static readonly Type ODataPath = typeof( ODataPath );
1114
static readonly Type ODataQueryOptions = typeof( ODataQueryOptions );
12-
static readonly Type DeltaType = typeof( IDelta );
15+
static readonly Type ODataActionParameters = typeof( ODataActionParameters );
16+
static readonly Type ODataParameterHelper = typeof( ODataParameterHelper );
1317

1418
internal static bool IsODataController( this Type controllerType ) => ODataController.IsAssignableFrom( controllerType );
1519

1620
internal static bool IsODataController( this TypeInfo controllerType ) => ODataController.IsAssignableFrom( controllerType );
1721

1822
internal static bool IsMetadataController( this TypeInfo controllerType ) => MetadataController.IsAssignableFrom( controllerType );
1923

24+
internal static bool IsODataPath( this Type type ) => ODataPath.IsAssignableFrom( type );
25+
2026
internal static bool IsODataQueryOptions( this Type type ) => ODataQueryOptions.IsAssignableFrom( type );
2127

22-
internal static bool IsDelta( this Type type ) => DeltaType.IsAssignableFrom( type );
28+
internal static bool IsODataActionParameters( this Type type ) => ODataActionParameters.IsAssignableFrom( type );
29+
30+
internal static bool IsDelta( this Type type ) => Delta.IsAssignableFrom( type );
31+
32+
internal static bool IsModelBound( this Type type ) =>
33+
ODataPath.IsAssignableFrom( type ) ||
34+
ODataQueryOptions.IsAssignableFrom( type ) ||
35+
Delta.IsAssignableFrom( type ) ||
36+
ODataActionParameters.IsAssignableFrom( type ) ||
37+
ODataParameterHelper.Equals( type );
2338
}
2439
}

src/Microsoft.AspNet.OData.Versioning.ApiExplorer/AspNet.OData/Routing/ODataRouteBuilderContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ internal ODataRouteBuilderContext(
3737
ApiVersion = apiVersion;
3838
serviceProvider = configuration.GetODataRootContainer( route );
3939
EdmModel = serviceProvider.GetRequiredService<IEdmModel>();
40-
AssembliesResolver = configuration.Services.GetAssembliesResolver();
40+
Assemblies = configuration.Services.GetAssembliesResolver().GetAssemblies();
4141
routeAttribute = actionDescriptor.GetCustomAttributes<ODataRouteAttribute>().FirstOrDefault();
4242
RouteTemplate = routeAttribute?.PathTemplate;
4343
Route = route;

src/Microsoft.AspNet.OData.Versioning.ApiExplorer/Microsoft.AspNet.OData.Versioning.ApiExplorer.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<AssemblyTitle>Microsoft ASP.NET Web API Versioned API Explorer for OData v4.0</AssemblyTitle>
88
<Description>The API Explorer for Microsoft ASP.NET Web API Versioning and OData v4.0.</Description>
99
<RootNamespace>Microsoft</RootNamespace>
10-
<DefineConstants>$(DefineConstants);WEBAPI</DefineConstants>
10+
<DefineConstants>$(DefineConstants);WEBAPI;API_EXPLORER</DefineConstants>
1111
<PackageTags>Microsoft;AspNet;AspNetWebAPI;Versioning;ApiExplorer;OData</PackageTags>
1212
</PropertyGroup>
1313

src/Microsoft.AspNet.OData.Versioning.ApiExplorer/Web.Http.Description/ODataApiExplorer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class ODataApiExplorer : VersionedApiExplorer
4646
public ODataApiExplorer( HttpConfiguration configuration, ODataApiExplorerOptions options ) : base( configuration, options )
4747
{
4848
Options = options;
49-
modelTypeBuilder = new ModelTypeBuilder( configuration.Services.GetAssembliesResolver() );
49+
modelTypeBuilder = new ModelTypeBuilder( configuration.Services.GetAssembliesResolver().GetAssemblies() );
5050
}
5151

5252
/// <summary>

0 commit comments

Comments
 (0)