Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions src/Common/Versioning/ApiVersionModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ internal ApiVersionModel(
}
else
{
declaredVersions = new Lazy<IReadOnlyList<ApiVersion>>( () => supported.Union( deprecated ).OrderBy( v => v ).ToArray() );
supportedVersions = new Lazy<IReadOnlyList<ApiVersion>>( () => supported.Union( advertised ).OrderBy( v => v ).ToArray() );
deprecatedVersions = new Lazy<IReadOnlyList<ApiVersion>>( () => deprecated.Union( deprecatedAdvertised ).OrderBy( v => v ).ToArray() );
implementedVersions = new Lazy<IReadOnlyList<ApiVersion>>( () => supportedVersions.Value.Union( deprecatedVersions.Value ).OrderBy( v => v ).ToArray() );
declaredVersions = new Lazy<IReadOnlyList<ApiVersion>>( supported.Union( deprecated ).ToSortedReadOnlyList );
supportedVersions = new Lazy<IReadOnlyList<ApiVersion>>( supported.Union( advertised ).ToSortedReadOnlyList );
deprecatedVersions = new Lazy<IReadOnlyList<ApiVersion>>( deprecated.Union( deprecatedAdvertised ).ToSortedReadOnlyList );
implementedVersions = new Lazy<IReadOnlyList<ApiVersion>>( () => supportedVersions.Value.Union( deprecatedVersions.Value ).ToSortedReadOnlyList() );
}
}

Expand Down Expand Up @@ -138,6 +138,33 @@ public ApiVersionModel( IEnumerable<ApiVersion> supportedVersions, IEnumerable<A
this.deprecatedVersions = new Lazy<IReadOnlyList<ApiVersion>>( deprecatedVersions.ToSortedReadOnlyList );
}

/// <summary>
/// Initializes a new instance of the <see cref="ApiVersionModel"/> class.
/// </summary>
/// <param name="declaredVersions">The declared <see cref="IEnumerable{T}">sequence</see> of <see cref="ApiVersion">API versions</see> on a controller or action.</param>
/// <param name="supportedVersions">The supported <see cref="IEnumerable{T}">sequence</see> of <see cref="ApiVersion">API versions</see> on a controller.</param>
/// <param name="deprecatedVersions">The deprecated <see cref="IEnumerable{T}">sequence</see> of <see cref="ApiVersion">API versions</see> on a controller.</param>
/// <param name="advertisedVersions">The advertised <see cref="IEnumerable{T}">sequence</see> of <see cref="ApiVersion">API versions</see> on a controller.</param>
/// <param name="deprecatedAdvertisedVersions">The deprecated, advertised <see cref="IEnumerable{T}">sequence</see> of <see cref="ApiVersion">API versions</see> on a controller.</param>
public ApiVersionModel(
IEnumerable<ApiVersion> declaredVersions,
IEnumerable<ApiVersion> supportedVersions,
IEnumerable<ApiVersion> deprecatedVersions,
IEnumerable<ApiVersion> advertisedVersions,
IEnumerable<ApiVersion> deprecatedAdvertisedVersions )
{
Arg.NotNull( declaredVersions, nameof( declaredVersions ) );
Arg.NotNull( supportedVersions, nameof( supportedVersions ) );
Arg.NotNull( deprecatedVersions, nameof( deprecatedVersions ) );
Arg.NotNull( advertisedVersions, nameof( advertisedVersions ) );
Arg.NotNull( deprecatedAdvertisedVersions, nameof( deprecatedAdvertisedVersions ) );

this.declaredVersions = new Lazy<IReadOnlyList<ApiVersion>>( declaredVersions.ToSortedReadOnlyList );
this.supportedVersions = new Lazy<IReadOnlyList<ApiVersion>>( supportedVersions.Union( advertisedVersions ).ToSortedReadOnlyList );
this.deprecatedVersions = new Lazy<IReadOnlyList<ApiVersion>>( deprecatedVersions.Union( deprecatedAdvertisedVersions ).ToSortedReadOnlyList );
this.implementedVersions = new Lazy<IReadOnlyList<ApiVersion>>( () => this.supportedVersions.Value.Union( this.deprecatedVersions.Value ).ToSortedReadOnlyList() );
}

private string DebuggerDisplayText => IsApiVersionNeutral ? "*.*" : string.Join( ", ", DeclaredApiVersions );

/// <summary>
Expand Down Expand Up @@ -198,4 +225,4 @@ public ApiVersionModel( IEnumerable<ApiVersion> supportedVersions, IEnumerable<A
/// controller would no longer indicate that it is an <see cref="ImplementedApiVersions">implemented version</see>.</remarks>
public IReadOnlyList<ApiVersion> DeprecatedApiVersions => deprecatedVersions.Value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ private ApiVersionModel()
deprecatedVersions = emptyVersions;
}

internal ApiVersionModel( HttpControllerDescriptor controllerDescriptor )
/// <summary>
/// Initializes a new instance of the <see cref="ApiVersionModel"/> class.
/// </summary>
/// <param name="controllerDescriptor">The <see cref="HttpControllerDescriptor"/> to initialize the API version model from.</param>
public ApiVersionModel( HttpControllerDescriptor controllerDescriptor )
{
Contract.Requires( controllerDescriptor != null );
Arg.NotNull( controllerDescriptor, nameof( controllerDescriptor ) );

if ( IsApiVersionNeutral = controllerDescriptor.GetCustomAttributes<IApiVersionNeutral>( false ).Any() )
{
Expand Down Expand Up @@ -61,9 +65,13 @@ internal ApiVersionModel( HttpControllerDescriptor controllerDescriptor, ApiVers
}
}

internal ApiVersionModel( HttpActionDescriptor actionDescriptor )
/// <summary>
/// Initializes a new instance of the <see cref="ApiVersionModel"/> class.
/// </summary>
/// <param name="actionDescriptor">The <see cref="HttpActionDescriptor"/> to initialize the API version model from.</param>
public ApiVersionModel( HttpActionDescriptor actionDescriptor )
{
Contract.Requires( actionDescriptor != null );
Arg.NotNull( actionDescriptor, nameof( actionDescriptor ) );

if ( IsApiVersionNeutral = actionDescriptor.ControllerDescriptor.GetCustomAttributes<IApiVersionNeutral>( false ).Any() )
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ public virtual ControllerApiVersionConventionBuilder<TController> Controller<TCo
/// </summary>
/// <param name="controllerDescriptor">The <see cref="HttpControllerDescriptor">controller descriptor</see>
/// to apply configured conventions to.</param>
public virtual void ApplyTo( HttpControllerDescriptor controllerDescriptor )
/// <returns>True if any conventions were applied to the
/// <paramref name="controllerDescriptor">controller descriptor</paramref>; otherwise, false.</returns>
public virtual bool ApplyTo( HttpControllerDescriptor controllerDescriptor )
{
Arg.NotNull( controllerDescriptor, nameof( controllerDescriptor ) );

Expand All @@ -60,7 +62,10 @@ public virtual void ApplyTo( HttpControllerDescriptor controllerDescriptor )
if ( ControllerConventions.TryGetValue( key, out convention ) )
{
convention.ApplyTo( controllerDescriptor );
return true;
}

return false;
}
}
}
28 changes: 0 additions & 28 deletions src/Microsoft.AspNetCore.Mvc.Versioning/ApiVersionAttribute.cs

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,6 @@
[CLSCompliant( false )]
public static class ModelExtensions
{
/// <summary>
/// Returns a value indicating whether controller model has explicit version information.
/// </summary>
/// <param name="controller">The <see cref="ControllerModel">model</see> to evaluate.</param>
/// <returns>True if the <paramref name="controller"/> has explicit version information; otherwise, false.</returns>
public static bool HasExplicitVersioning( this ControllerModel controller )
{
Arg.NotNull( controller, nameof( controller ) );
return controller.Properties.ContainsKey( typeof( ApiVersionModel ) ) || controller.Attributes.OfType<IApiVersionProvider>().Any();
}

/// <summary>
/// Gets the property associated with the controller model.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,7 @@ public static IServiceCollection AddApiVersioning( this IServiceCollection servi
mvcOptions.Filters.Add( typeof( ReportApiVersionsAttribute ) );
}

if ( options.Conventions.Count > 0 )
{
mvcOptions.Conventions.Add( new ApiVersionConvention( options.Conventions ) );
}

mvcOptions.Conventions.Add( new ImplicitControllerVersionConvention( options.DefaultApiVersion ) );
mvcOptions.Conventions.Add( new ApiVersionConvention( options.DefaultApiVersion, options.Conventions ) );
} );

services.AddRouting( mvcOptions => mvcOptions.ConstraintMap.Add( "apiVersion", typeof( ApiVersionRouteConstraint ) ) );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using ApplicationModels;
using Conventions;
using System;
using System.Diagnostics.Contracts;

/// <summary>
/// Represents an <see cref="IApplicationModelConvention">application model convention</see> which applies
Expand All @@ -12,15 +13,43 @@
public class ApiVersionConvention : IApplicationModelConvention
{
private readonly ApiVersionConventionBuilder conventionBuilder;
private readonly ApiVersionModel implicitVersionModel;

/// <summary>
/// Initializes a new instance of the <see cref="ApiVersionConvention"/> class.
/// </summary>
public ApiVersionConvention()
{
implicitVersionModel = ApiVersionModel.Default;
conventionBuilder = new ApiVersionConventionBuilder();
}

/// <summary>
/// Initializes a new instance of the <see cref="ApiVersionConvention"/> class.
/// </summary>
/// <param name="implicitlyDeclaredVersion">The implicitly declared <see cref="ApiVersion">API version</see> for
/// controllers and actions that have no other API versioning information applied.</param>
public ApiVersionConvention( ApiVersion implicitlyDeclaredVersion )
{
Arg.NotNull( implicitlyDeclaredVersion, nameof( implicitlyDeclaredVersion ) );

implicitVersionModel = new ApiVersionModel( implicitlyDeclaredVersion );
conventionBuilder = new ApiVersionConventionBuilder();
}

/// <summary>
/// Initializes a new instance of the <see cref="ApiVersionConvention"/> class.
/// </summary>
/// <param name="implicitlyDeclaredVersion">The implicitly declared <see cref="ApiVersion">API version</see> for
/// controllers and actions that have no other API versioning information applied.</param>
/// <param name="conventionBuilder">The <see cref="ApiVersionConventionBuilder">convention builder</see>
/// containing the configured conventions to aply.</param>
public ApiVersionConvention( ApiVersionConventionBuilder conventionBuilder )
/// containing the configured conventions to apply.</param>
public ApiVersionConvention( ApiVersion implicitlyDeclaredVersion, ApiVersionConventionBuilder conventionBuilder )
{
Arg.NotNull( implicitlyDeclaredVersion, nameof( implicitlyDeclaredVersion ) );
Arg.NotNull( conventionBuilder, nameof( conventionBuilder ) );

implicitVersionModel = new ApiVersionModel( implicitlyDeclaredVersion );
this.conventionBuilder = conventionBuilder;
}

Expand All @@ -30,9 +59,64 @@ public ApiVersionConvention( ApiVersionConventionBuilder conventionBuilder )
/// <param name="application">The <see cref="ApplicationModel">application</see> to apply the convention to.</param>
public void Apply( ApplicationModel application )
{
foreach ( var controller in application.Controllers )
if ( conventionBuilder.Count == 0 )
{
foreach ( var controller in application.Controllers )
{
ApplyAttributeOrImplicitConventions( controller );
}
}
else
{
foreach ( var controller in application.Controllers )
{
if ( !conventionBuilder.ApplyTo( controller ) )
{
ApplyAttributeOrImplicitConventions( controller );
}
}
}
}

private static bool IsDecoratedWithAttributes( ControllerModel controller )
{
Contract.Requires( controller != null );

foreach ( var attribute in controller.Attributes )
{
if ( attribute is IApiVersionProvider || attribute is IApiVersionNeutral )
{
return true;
}
}

return false;
}

private void ApplyImplicitConventions( ControllerModel controller )
{
Contract.Requires( controller != null );

controller.SetProperty( implicitVersionModel );

foreach ( var action in controller.Actions )
{
action.SetProperty( implicitVersionModel );
}
}

private void ApplyAttributeOrImplicitConventions( ControllerModel controller )
{
Contract.Requires( controller != null );

if ( IsDecoratedWithAttributes( controller ) )
{
var conventions = new ControllerApiVersionConventionBuilder<ControllerModel>();
conventions.ApplyTo( controller );
}
else
{
conventionBuilder.ApplyTo( controller );
ApplyImplicitConventions( controller );
}
}
}
Expand Down
Loading