Skip to content

Commit c73f931

Browse files
Chris Martinezcommonsensesoftware
authored andcommitted
Optimize model builder to improve startup
1 parent 56adf77 commit c73f931

File tree

4 files changed

+74
-58
lines changed

4 files changed

+74
-58
lines changed

src/Common.OData/AspNet.OData/Builder/VersionedODataModelBuilder.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,26 @@ public Func<ODataModelBuilder> ModelBuilderFactory
6060
/// value is <c>null</c>.</value>
6161
public Action<ODataModelBuilder, IEdmModel> OnModelCreated { get; set; }
6262

63-
IEnumerable<IModelConfiguration> GetMergedConfigurations()
63+
/// <summary>
64+
/// Builds and returns the sequence of EDM models based on the define model configurations.
65+
/// </summary>
66+
/// <returns>A <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see>.</returns>
67+
public virtual IEnumerable<IEdmModel> GetEdmModels()
68+
{
69+
Contract.Ensures( Contract.Result<IEnumerable<IEdmModel>>() != null );
70+
71+
var apiVersions = GetApiVersions();
72+
var configurations = GetMergedConfigurations();
73+
var models = new List<IEdmModel>();
74+
75+
BuildModelPerApiVersion( apiVersions, configurations, models );
76+
77+
return models;
78+
}
79+
80+
IList<IModelConfiguration> GetMergedConfigurations()
6481
{
65-
Contract.Ensures( Contract.Result<IEnumerable<IModelConfiguration>>() != null );
82+
Contract.Ensures( Contract.Result<IList<IModelConfiguration>>() != null );
6683

6784
var defaultConfiguration = DefaultModelConfiguration;
6885

@@ -79,19 +96,20 @@ IEnumerable<IModelConfiguration> GetMergedConfigurations()
7996
return configurations;
8097
}
8198

82-
void BuildModelPerApiVersion( IEnumerable<ApiVersion> apiVersions, IEnumerable<IModelConfiguration> configurations, ICollection<IEdmModel> models )
99+
void BuildModelPerApiVersion( IReadOnlyList<ApiVersion> apiVersions, IList<IModelConfiguration> configurations, ICollection<IEdmModel> models )
83100
{
84101
Contract.Requires( apiVersions != null );
85102
Contract.Requires( configurations != null );
86103
Contract.Requires( models != null );
87104

88-
foreach ( var apiVersion in apiVersions )
105+
for ( var i = 0; i < apiVersions.Count; i++ )
89106
{
107+
var apiVersion = apiVersions[i];
90108
var builder = ModelBuilderFactory();
91109

92-
foreach ( var configuration in configurations )
110+
for ( var j = 0; j < configurations.Count; j++ )
93111
{
94-
configuration.Apply( builder, apiVersion );
112+
configurations[j].Apply( builder, apiVersion );
95113
}
96114

97115
var model = builder.GetEdmModel();

src/Microsoft.AspNet.OData.Versioning/Builder/VersionedODataModelBuilder.cs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
namespace Microsoft.AspNet.OData.Builder
22
{
3-
using Microsoft.OData.Edm;
43
using Microsoft.Web.Http;
54
using Microsoft.Web.Http.Versioning;
65
using Microsoft.Web.Http.Versioning.Conventions;
@@ -44,16 +43,14 @@ public VersionedODataModelBuilder( HttpConfiguration configuration )
4443
protected ApiVersioningOptions Options => Configuration.GetApiVersioningOptions();
4544

4645
/// <summary>
47-
/// Builds and returns the sequence of EDM models based on the define model configurations.
46+
/// Gets the API versions for all known OData routes.
4847
/// </summary>
49-
/// <returns>A <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see>.</returns>
50-
[SuppressMessage( "Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Matches plural form of ODataModelBuilder.GetEdmModel(). A property would also not be appropriate." )]
51-
public virtual IEnumerable<IEdmModel> GetEdmModels()
48+
/// <returns>The <see cref="IReadOnlyList{T}">sequence</see> of <see cref="ApiVersion">API versions</see>
49+
/// for all known OData routes.</returns>
50+
protected virtual IReadOnlyList<ApiVersion> GetApiVersions()
5251
{
53-
Contract.Ensures( Contract.Result<IEnumerable<IEdmModel>>() != null );
52+
Contract.Ensures( Contract.Result<IReadOnlyList<ApiVersion>>() != null );
5453

55-
var configurations = GetMergedConfigurations();
56-
var models = new List<IEdmModel>();
5754
var services = Configuration.Services;
5855
var assembliesResolver = services.GetAssembliesResolver();
5956
var typeResolver = services.GetHttpControllerTypeResolver();
@@ -69,23 +66,31 @@ public virtual IEnumerable<IEdmModel> GetEdmModels()
6966
conventions.ApplyTo( descriptor );
7067

7168
var model = descriptor.GetApiVersionModel();
69+
var versions = model.SupportedApiVersions;
7270

73-
foreach ( var apiVersion in model.SupportedApiVersions )
71+
for ( var i = 0; i < versions.Count; i++ )
7472
{
75-
supported.Add( apiVersion );
73+
supported.Add( versions[i] );
7674
}
7775

78-
foreach ( var apiVersion in model.DeprecatedApiVersions )
76+
versions = model.DeprecatedApiVersions;
77+
78+
for ( var i = 0; i < versions.Count; i++ )
7979
{
80-
deprecated.Add( apiVersion );
80+
deprecated.Add( versions[i] );
8181
}
8282
}
8383

8484
deprecated.ExceptWith( supported );
85-
BuildModelPerApiVersion( supported.Union( deprecated ), configurations, models );
85+
86+
if ( supported.Count == 0 && deprecated.Count == 0 )
87+
{
88+
supported.Add( Options.DefaultApiVersion );
89+
}
90+
8691
ConfigureMetadataController( supported, deprecated );
8792

88-
return models;
93+
return supported.Union( deprecated ).ToArray();
8994
}
9095

9196
/// <summary>

src/Microsoft.AspNetCore.OData.Versioning/AspNet.OData/Builder/VersionedODataModelBuilder.cs

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
using Microsoft.AspNetCore.Mvc.Infrastructure;
77
using Microsoft.AspNetCore.Mvc.Versioning;
88
using Microsoft.Extensions.Options;
9-
using Microsoft.OData.Edm;
109
using System;
1110
using System.Collections.Generic;
1211
using System.Diagnostics.Contracts;
13-
using System.Linq;
1412
using static System.Linq.Enumerable;
1513

1614
/// <content>
@@ -66,38 +64,24 @@ public VersionedODataModelBuilder(
6664
/// <value>The associated <see cref="ApiVersioningOptions">API versioning options</see>.</value>
6765
protected ApiVersioningOptions Options => options.Value;
6866

69-
/// <summary>
70-
/// Builds and returns the sequence of EDM models based on the define model configurations.
71-
/// </summary>
72-
/// <returns>A <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see>.</returns>
73-
public virtual IEnumerable<IEdmModel> GetEdmModels()
74-
{
75-
Contract.Ensures( Contract.Result<IEnumerable<IEdmModel>>() != null );
76-
77-
var apiVersions = GetApiVersions();
78-
var configurations = GetMergedConfigurations();
79-
var models = new List<IEdmModel>();
80-
81-
BuildModelPerApiVersion( apiVersions, configurations, models );
82-
83-
return models;
84-
}
85-
8667
/// <summary>
8768
/// Gets the API versions for all known OData routes.
8869
/// </summary>
89-
/// <returns>The <see cref="IEnumerable{T}">sequence</see> of <see cref="ApiVersion">API versions</see>
70+
/// <returns>The <see cref="IReadOnlyList{T}">sequence</see> of <see cref="ApiVersion">API versions</see>
9071
/// for all known OData routes.</returns>
91-
protected virtual IEnumerable<ApiVersion> GetApiVersions()
72+
protected virtual IReadOnlyList<ApiVersion> GetApiVersions()
9273
{
93-
Contract.Ensures( Contract.Result<IEnumerable<ApiVersion>>() != null );
74+
Contract.Ensures( Contract.Result<IReadOnlyList<ApiVersion>>() != null );
9475

95-
var actions = ActionDescriptorCollectionProvider.ActionDescriptors.Items.OfType<ControllerActionDescriptor>();
96-
var implemented = new HashSet<ApiVersion>();
76+
var items = ActionDescriptorCollectionProvider.ActionDescriptors.Items;
77+
var supported = new HashSet<ApiVersion>();
78+
var deprecated = new HashSet<ApiVersion>();
9779

98-
foreach ( var action in actions )
80+
for ( var i = 0; i < items.Count; i++ )
9981
{
100-
if ( !action.ControllerTypeInfo.IsODataController() )
82+
var item = items[i];
83+
84+
if ( !( item is ControllerActionDescriptor action ) || !action.ControllerTypeInfo.IsODataController() )
10185
{
10286
continue;
10387
}
@@ -109,25 +93,29 @@ protected virtual IEnumerable<ApiVersion> GetApiVersions()
10993
continue;
11094
}
11195

112-
foreach ( var apiVersion in model.ImplementedApiVersions )
96+
var versions = model.SupportedApiVersions;
97+
98+
for ( var j = 0; j < versions.Count; j++ )
11399
{
114-
implemented.Add( apiVersion );
100+
supported.Add( versions[j] );
115101
}
116-
}
117102

118-
if ( implemented.Count == 0 )
119-
{
120-
implemented.Add( Options.DefaultApiVersion );
103+
versions = model.DeprecatedApiVersions;
104+
105+
for ( var j = 0; j < versions.Count; j++ )
106+
{
107+
deprecated.Add( versions[j] );
108+
}
121109
}
122110

123-
var apiVersions = implemented.ToArray();
111+
deprecated.ExceptWith( supported );
124112

125-
if ( apiVersions.Length > 1 )
113+
if ( supported.Count == 0 && deprecated.Count == 0 )
126114
{
127-
Array.Sort( apiVersions );
115+
supported.Add( Options.DefaultApiVersion );
128116
}
129117

130-
return apiVersions;
118+
return supported.Union( deprecated ).ToArray();
131119
}
132120
}
133121
}

test/Microsoft.AspNetCore.OData.Versioning.ApiExplorer.Tests/AspNetCore.Mvc.ApiExplorer/ODataApiDescriptionProviderTest.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.AspNetCore.Hosting;
88
using Microsoft.AspNetCore.TestHost;
99
using Microsoft.Extensions.DependencyInjection;
10+
using System.Linq;
1011
using Xunit;
1112

1213
public class ODataApiDescriptionProviderTest
@@ -33,10 +34,14 @@ public void odata_api_explorer_should_group_and_order_descriptions_on_providers_
3334
var serviceProvider = server.Host.Services;
3435

3536
// act
36-
var groups = serviceProvider.GetRequiredService<IApiDescriptionGroupCollectionProvider>().ApiDescriptionGroups.Items;
37+
var groups = serviceProvider.GetRequiredService<IApiDescriptionGroupCollectionProvider>()
38+
.ApiDescriptionGroups
39+
.Items
40+
.OrderBy( i => i.GroupName )
41+
.ToArray();
3742

3843
// assert
39-
groups.Count.Should().Be( 4 );
44+
groups.Length.Should().Be( 4 );
4045
AssertVersion0_9( groups[0] );
4146
AssertVersion1( groups[1] );
4247
AssertVersion2( groups[2] );

0 commit comments

Comments
 (0)