Skip to content

Commit 79b3e28

Browse files
author
Chris Martinez
committed
Ensure implicitly versioned ActionModel has associated ControllerModel. Fixes #519
1 parent d038f67 commit 79b3e28

File tree

3 files changed

+54
-24
lines changed

3 files changed

+54
-24
lines changed

src/Microsoft.AspNetCore.Mvc.Versioning/Versioning/ApiVersioningApplicationModelProvider.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ public virtual void OnProvidersExecuted( ApplicationModelProviderContext context
5959
controllers = ControllerFilter.Apply( controllers );
6060
}
6161

62-
foreach ( var controller in controllers )
62+
for ( var i = 0; i < controllers.Count; i++ )
6363
{
64+
var controller = controllers[i];
65+
6466
if ( !conventionBuilder.ApplyTo( controller ) )
6567
{
6668
ApplyAttributeOrImplicitConventions( controller, implicitVersionModel );
@@ -75,8 +77,10 @@ static bool IsDecoratedWithAttributes( ControllerModel controller )
7577
{
7678
Contract.Requires( controller != null );
7779

78-
foreach ( var attribute in controller.Attributes )
80+
for ( var i = 0; i < controller.Attributes.Count; i++ )
7981
{
82+
var attribute = controller.Attributes[i];
83+
8084
if ( attribute is IApiVersionProvider || attribute is IApiVersionNeutral )
8185
{
8286
return true;
@@ -91,8 +95,10 @@ static void ApplyImplicitConventions( ControllerModel controller, ApiVersionMode
9195
Contract.Requires( controller != null );
9296
Contract.Requires( implicitVersionModel != null );
9397

94-
foreach ( var action in controller.Actions )
98+
for ( var i = 0; i < controller.Actions.Count; i++ )
9599
{
100+
var action = controller.Actions[i];
101+
action.SetProperty( controller );
96102
action.SetProperty( implicitVersionModel );
97103
}
98104
}

src/Microsoft.AspNetCore.OData.Versioning.ApiExplorer/AspNetCore.Mvc.ApiExplorer/ODataApiDescriptionProvider.cs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
using Microsoft.AspNetCore.Mvc.Abstractions;
99
using Microsoft.AspNetCore.Mvc.ActionConstraints;
1010
using Microsoft.AspNetCore.Mvc.ApplicationModels;
11-
using Microsoft.AspNetCore.Mvc.ApplicationParts;
1211
using Microsoft.AspNetCore.Mvc.Controllers;
1312
using Microsoft.AspNetCore.Mvc.Formatters;
1413
using Microsoft.AspNetCore.Mvc.Internal;
1514
using Microsoft.AspNetCore.Mvc.ModelBinding;
16-
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
1715
using Microsoft.AspNetCore.Mvc.Routing;
1816
using Microsoft.AspNetCore.Routing;
1917
using Microsoft.AspNetCore.Routing.Template;
@@ -26,7 +24,6 @@
2624
using System.Diagnostics.Contracts;
2725
using System.Globalization;
2826
using System.Linq;
29-
using System.Reflection;
3027
using System.Threading.Tasks;
3128
using static Microsoft.AspNet.OData.Routing.ODataRouteActionType;
3229
using static Microsoft.AspNetCore.Http.StatusCodes;
@@ -132,9 +129,9 @@ public ODataApiDescriptionProvider(
132129
protected MvcOptions MvcOptions { get; }
133130

134131
/// <summary>
135-
/// Gets the order prescendence of the current API description provider.
132+
/// Gets the order precedence of the current API description provider.
136133
/// </summary>
137-
/// <value>The order prescendence of the current API description provider. The default value is -100.</value>
134+
/// <value>The order precedence of the current API description provider. The default value is -100.</value>
138135
public virtual int Order => AfterApiVersioning;
139136

140137
/// <summary>
@@ -144,10 +141,8 @@ public ODataApiDescriptionProvider(
144141
/// <remarks>The default implementation performs no action.</remarks>
145142
public virtual void OnProvidersExecuted( ApiDescriptionProviderContext context )
146143
{
147-
var ignoreApiExplorerSettings = !Options.UseApiExplorerSettings;
148144
var mappings = RouteCollectionProvider.Items;
149145
var results = context.Results;
150-
151146
var groupNameFormat = Options.GroupNameFormat;
152147
var formatProvider = CultureInfo.CurrentCulture;
153148

@@ -164,8 +159,9 @@ public virtual void OnProvidersExecuted( ApiDescriptionProviderContext context )
164159

165160
if ( model.IsApiVersionNeutral )
166161
{
167-
foreach ( var mapping in mappings )
162+
for ( var i = 0; i < mappings.Count; i++ )
168163
{
164+
var mapping = mappings[i];
169165
var descriptions = new List<ApiDescription>();
170166
var groupName = mapping.ApiVersion.ToString( groupNameFormat, formatProvider );
171167

@@ -183,17 +179,19 @@ public virtual void OnProvidersExecuted( ApiDescriptionProviderContext context )
183179
}
184180
else
185181
{
186-
foreach ( var apiVersion in model.DeclaredApiVersions )
182+
for ( var i = 0; i < model.DeclaredApiVersions.Count; i++ )
187183
{
184+
var apiVersion = model.DeclaredApiVersions[i];
188185
var groupName = apiVersion.ToString( groupNameFormat, formatProvider );
189186

190187
if ( !mappings.TryGetValue( apiVersion, out var mappingsPerApiVersion ) )
191188
{
192189
continue;
193190
}
194191

195-
foreach ( var mapping in mappingsPerApiVersion )
192+
for ( var j = 0; j < mappingsPerApiVersion.Count; j++ )
196193
{
194+
var mapping = mappingsPerApiVersion[j];
197195
var descriptions = new List<ApiDescription>();
198196

199197
foreach ( var apiDescription in NewODataApiDescriptions( action, groupName, mapping ) )
@@ -364,7 +362,7 @@ static string BuildRelativePath( ControllerActionDescriptor action, ODataRouteBu
364362

365363
var relativePath = action.AttributeRouteInfo?.Template;
366364

367-
// note: if path happens to be built adhead of time, it's expected to be qualified; rebuild it as necessary
365+
// note: if path happens to be built ahead of time, it's expected to be qualified; rebuild it as necessary
368366
if ( string.IsNullOrEmpty( relativePath ) || !routeContext.Options.UseQualifiedNames )
369367
{
370368
var builder = new ODataRouteBuilder( routeContext );
@@ -422,14 +420,15 @@ IEnumerable<ApiDescription> NewODataApiDescriptions( ControllerActionDescriptor
422420
apiDescription.Properties[typeof( IEdmOperation )] = routeContext.Operation;
423421
}
424422

425-
foreach ( var parameter in parameters )
423+
for ( var i = 0; i < parameters.Count; i++ )
426424
{
425+
var parameter = parameters[i];
427426
apiDescription.ParameterDescriptions.Add( parameter );
428427
}
429428

430-
foreach ( var apiResponseType in apiResponseTypes )
429+
for ( var i = 0; i < apiResponseTypes.Count; i++ )
431430
{
432-
apiDescription.SupportedResponseTypes.Add( apiResponseType );
431+
apiDescription.SupportedResponseTypes.Add( apiResponseTypes[i] );
433432
}
434433

435434
PopulateApiVersionParameters( apiDescription, mapping.ApiVersion );
@@ -445,8 +444,9 @@ IList<ApiParameterDescription> GetParameters( ApiParameterContext context )
445444

446445
if ( action.Parameters != null )
447446
{
448-
foreach ( var actionParameter in action.Parameters )
447+
for ( var i = 0; i < action.Parameters.Count; i++ )
449448
{
449+
var actionParameter = action.Parameters[i];
450450
var metadata = MetadataProvider.GetMetadataForType( actionParameter.ParameterType );
451451

452452
UpdateBindingInfo( context, actionParameter, metadata );
@@ -460,8 +460,9 @@ IList<ApiParameterDescription> GetParameters( ApiParameterContext context )
460460

461461
if ( action.BoundProperties != null )
462462
{
463-
foreach ( var actionParameter in action.BoundProperties )
463+
for ( var i = 0; i < action.BoundProperties.Count; i++ )
464464
{
465+
var actionParameter = action.BoundProperties[i];
465466
var visitor = new PseudoModelBindingVisitor( context, actionParameter );
466467
var modelMetadata = context.MetadataProvider.GetMetadataForProperty(
467468
containerType: action.ControllerTypeInfo.AsType(),

src/Microsoft.AspNetCore.OData.Versioning/AspNetCore.Mvc/Versioning/ApiExplorerModelConvention.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,53 @@
22
{
33
using Microsoft.AspNet.OData;
44
using Microsoft.AspNetCore.Mvc.ApplicationModels;
5+
using System.Linq;
56

67
sealed class ApiExplorerModelConvention : IApplicationModelConvention
78
{
89
public void Apply( ApplicationModel application )
910
{
10-
foreach ( var controller in application.Controllers )
11+
for ( var i = 0; i < application.Controllers.Count; i++ )
1112
{
13+
var controller = application.Controllers[i];
14+
1215
if ( !controller.ControllerType.IsODataController() )
1316
{
1417
continue;
1518
}
1619

17-
if ( controller.ApiExplorer != null )
20+
if ( controller.ApiExplorer == null )
21+
{
22+
var model = new ApiExplorerModel();
23+
var attribute = controller.Attributes.OfType<ApiExplorerSettingsAttribute>().FirstOrDefault();
24+
25+
if ( attribute != null )
26+
{
27+
model.GroupName = attribute.GroupName;
28+
model.IsVisible = !attribute.IgnoreApi;
29+
}
30+
31+
controller.ApiExplorer = new ODataApiExplorerModel( model );
32+
}
33+
else if ( !( controller.ApiExplorer is ODataApiExplorerModel ) )
1834
{
1935
controller.ApiExplorer = new ODataApiExplorerModel( controller.ApiExplorer );
2036
}
2137

22-
foreach ( var action in controller.Actions )
38+
for ( var j = 0; j < controller.Actions.Count; j++ )
2339
{
24-
if ( action.ApiExplorer != null )
40+
var action = controller.Actions[j];
41+
42+
if ( action.ApiExplorer == null )
43+
{
44+
action.ApiExplorer = controller.ApiExplorer;
45+
}
46+
else if ( !( action.ApiExplorer is ODataApiExplorerModel ) )
2547
{
2648
action.ApiExplorer = new ODataApiExplorerModel( action.ApiExplorer );
27-
action.SetProperty( action.ApiExplorer );
2849
}
50+
51+
action.SetProperty( action.ApiExplorer );
2952
}
3053
}
3154
}

0 commit comments

Comments
 (0)