Skip to content

Commit 3f529d3

Browse files
Chris Martinezcommonsensesoftware
authored andcommitted
Add support for non-generic API version conventions. Resolves dotnet#196
1 parent a48ab14 commit 3f529d3

File tree

48 files changed

+3544
-489
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3544
-489
lines changed

src/Common/Common.projitems

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,21 @@
3030
<Compile Include="$(MSBuildThisFileDirectory)Versioning\ApiVersionsBaseAttribute.cs" />
3131
<Compile Include="$(MSBuildThisFileDirectory)Versioning\AttributeExtensions.cs" />
3232
<Compile Include="$(MSBuildThisFileDirectory)Versioning\ConstantApiVersionSelector.cs" />
33+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionApiVersionConventionBuilderCollection.cs" />
3334
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionApiVersionConventionBuilderCollectionT.cs" />
35+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionApiVersionConventionBuilderBase.cs" />
36+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionApiVersionConventionBuilder.cs" />
3437
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionApiVersionConventionBuilderT.cs" />
38+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionApiVersionConventionBuilderExtensions.cs" />
3539
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionApiVersionConventionBuilderTExtensions.cs" />
36-
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionConventionBuilderTExtensions.cs" />
40+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ActionConventionBuilderExtensions.cs" />
41+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ControllerApiVersionConventionBuilderBase.cs" />
42+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ControllerApiVersionConventionBuilder.cs" />
3743
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ControllerApiVersionConventionBuilderT.cs" />
44+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ControllerApiVersionConventionBuilderExtensions.cs" />
3845
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ControllerApiVersionConventionBuilderTExtensions.cs" />
3946
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\ExpressionExtensions.cs" />
47+
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\IActionConventionBuilder.cs" />
4048
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\IActionConventionBuilderT.cs" />
4149
<Compile Include="$(MSBuildThisFileDirectory)Versioning\Conventions\IApiVersionConventionT.cs" />
4250
<Compile Include="$(MSBuildThisFileDirectory)Versioning\CurrentImplementationApiVersionSelector.cs" />
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#if WEBAPI
2+
namespace Microsoft.Web.Http.Versioning.Conventions
3+
#else
4+
namespace Microsoft.AspNetCore.Mvc.Versioning.Conventions
5+
#endif
6+
{
7+
using System;
8+
using System.Diagnostics.Contracts;
9+
using System.Reflection;
10+
11+
/// <summary>
12+
/// Represents a builder for API versions applied to a controller action.
13+
/// </summary>
14+
public partial class ActionApiVersionConventionBuilder : ActionApiVersionConventionBuilderBase
15+
{
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="ActionApiVersionConventionBuilder"/> class.
18+
/// </summary>
19+
/// <param name="controllerBuilder">The <see cref="ControllerApiVersionConventionBuilder">controller builder</see>
20+
/// the action builder belongs to.</param>
21+
public ActionApiVersionConventionBuilder( ControllerApiVersionConventionBuilder controllerBuilder )
22+
{
23+
Arg.NotNull( controllerBuilder, nameof( controllerBuilder ) );
24+
ControllerBuilder = controllerBuilder;
25+
}
26+
27+
/// <summary>
28+
/// Gets the controller builder the action builder belongs to.
29+
/// </summary>
30+
/// <value>The associated <see cref="ControllerApiVersionConventionBuilder"/>.</value>
31+
protected ControllerApiVersionConventionBuilder ControllerBuilder { get; }
32+
33+
/// <summary>
34+
/// Gets the type of controller the convention builder is for.
35+
/// </summary>
36+
/// <value>The corresponding controller <see cref="Type">type</see>.</value>
37+
public Type ControllerType => ControllerBuilder.ControllerType;
38+
39+
/// <summary>
40+
/// Maps the specified API version to the configured controller action.
41+
/// </summary>
42+
/// <param name="apiVersion">The <see cref="ApiVersion">API version</see> to map to the action.</param>
43+
/// <returns>The original <see cref="ActionApiVersionConventionBuilder"/>.</returns>
44+
public virtual ActionApiVersionConventionBuilder MapToApiVersion( ApiVersion apiVersion )
45+
{
46+
Arg.NotNull( apiVersion, nameof( apiVersion ) );
47+
Contract.Ensures( Contract.Result<ActionApiVersionConventionBuilder>() != null );
48+
49+
MappedVersions.Add( apiVersion );
50+
return this;
51+
}
52+
53+
/// <summary>
54+
/// Gets or creates the convention builder for the specified controller action method.
55+
/// </summary>
56+
/// <param name="actionMethod">The <see cref="MethodInfo">method</see> representing the controller action.</param>
57+
/// <returns>A new or existing <see cref="ActionApiVersionConventionBuilder"/>.</returns>
58+
public virtual ActionApiVersionConventionBuilder Action( MethodInfo actionMethod ) => ControllerBuilder.Action( actionMethod );
59+
}
60+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#if WEBAPI
2+
namespace Microsoft.Web.Http.Versioning.Conventions
3+
#else
4+
namespace Microsoft.AspNetCore.Mvc.Versioning.Conventions
5+
#endif
6+
{
7+
using System;
8+
using System.Collections.Generic;
9+
10+
/// <summary>
11+
/// Represents the base implementation of a builder for API versions applied to a controller action.
12+
/// </summary>
13+
public partial class ActionApiVersionConventionBuilderBase
14+
{
15+
readonly HashSet<ApiVersion> mappedVersions = new HashSet<ApiVersion>();
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="ActionApiVersionConventionBuilderBase"/> class.
19+
/// </summary>
20+
protected ActionApiVersionConventionBuilderBase() { }
21+
22+
/// <summary>
23+
/// Gets the collection of API versions mapped to the current action.
24+
/// </summary>
25+
/// <value>A <see cref="ICollection{T}">collection</see> of mapped <see cref="ApiVersion">API versions</see>.</value>
26+
protected ICollection<ApiVersion> MappedVersions => mappedVersions;
27+
}
28+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#if WEBAPI
2+
namespace Microsoft.Web.Http.Versioning.Conventions
3+
#else
4+
namespace Microsoft.AspNetCore.Mvc.Versioning.Conventions
5+
#endif
6+
{
7+
using System;
8+
using System.Collections;
9+
using System.Collections.Generic;
10+
using System.Diagnostics.Contracts;
11+
using System.Linq;
12+
using System.Reflection;
13+
14+
/// <summary>
15+
/// Represents a collection of controller action convention builders.
16+
/// </summary>
17+
#if !WEBAPI
18+
[CLSCompliant( false )]
19+
#endif
20+
public class ActionApiVersionConventionBuilderCollection : IReadOnlyCollection<ActionApiVersionConventionBuilder>
21+
{
22+
readonly ControllerApiVersionConventionBuilder controllerBuilder;
23+
readonly IList<ActionBuilderMapping> actionBuilderMappings = new List<ActionBuilderMapping>();
24+
25+
/// <summary>
26+
/// Initializes a new instance of the <see cref="ActionApiVersionConventionBuilderCollection"/> class.
27+
/// </summary>
28+
/// <param name="controllerBuilder">The associated <see cref="ControllerApiVersionConventionBuilder">controller convention builder</see>.</param>
29+
public ActionApiVersionConventionBuilderCollection( ControllerApiVersionConventionBuilder controllerBuilder )
30+
{
31+
Arg.NotNull( controllerBuilder, nameof( controllerBuilder ) );
32+
this.controllerBuilder = controllerBuilder;
33+
}
34+
35+
/// <summary>
36+
/// Gets or adds a controller action convention builder for the specified method.
37+
/// </summary>
38+
/// <param name="actionMethod">The controller action method to get or add the convention builder for.</param>
39+
/// <returns>A new or existing <see cref="ActionApiVersionConventionBuilder">controller action convention builder</see>.</returns>
40+
protected internal virtual ActionApiVersionConventionBuilder GetOrAdd( MethodInfo actionMethod )
41+
{
42+
Arg.NotNull( actionMethod, nameof( actionMethod ) );
43+
44+
var mapping = actionBuilderMappings.FirstOrDefault( m => m.Method == actionMethod );
45+
46+
if ( mapping == null )
47+
{
48+
mapping = new ActionBuilderMapping( actionMethod, new ActionApiVersionConventionBuilder( controllerBuilder ) );
49+
actionBuilderMappings.Add( mapping );
50+
}
51+
52+
return mapping.Builder;
53+
}
54+
55+
/// <summary>
56+
/// Gets a count of the controller action convention builders in the collection.
57+
/// </summary>
58+
/// <value>The total number of controller action convention builders in the collection.</value>
59+
public virtual int Count => actionBuilderMappings.Count;
60+
61+
/// <summary>
62+
/// Attempts to retrieve the controller action convention builder for the specified method.
63+
/// </summary>
64+
/// <param name="actionMethod">The controller action method to get the convention builder for.</param>
65+
/// <param name="actionBuilder">The <see cref="ActionApiVersionConventionBuilder">controller action convention builder</see> or <c>null</c>.</param>
66+
/// <returns>True if the <paramref name="actionBuilder">action builder</paramref> is successfully retrieved; otherwise, false.</returns>
67+
public virtual bool TryGetValue( MethodInfo actionMethod, out ActionApiVersionConventionBuilder actionBuilder )
68+
{
69+
actionBuilder = null;
70+
71+
if ( actionMethod == null )
72+
{
73+
return false;
74+
}
75+
76+
var mapping = actionBuilderMappings.FirstOrDefault( m => m.Method == actionMethod );
77+
78+
return ( actionBuilder = mapping?.Builder ) != null;
79+
}
80+
81+
/// <summary>
82+
/// Returns an iterator that enumerates the controller action convention builders in the collection.
83+
/// </summary>
84+
/// <returns>An <see cref="IEnumerator"/> object.</returns>
85+
public virtual IEnumerator<ActionApiVersionConventionBuilder> GetEnumerator()
86+
{
87+
foreach ( var mapping in actionBuilderMappings )
88+
{
89+
yield return mapping.Builder;
90+
}
91+
}
92+
93+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
94+
95+
sealed partial class ActionBuilderMapping
96+
{
97+
internal ActionBuilderMapping( MethodInfo method, ActionApiVersionConventionBuilder builder )
98+
{
99+
Contract.Requires( method != null );
100+
Contract.Requires( builder != null );
101+
102+
Method = method;
103+
Builder = builder;
104+
}
105+
106+
internal MethodInfo Method { get; }
107+
108+
internal ActionApiVersionConventionBuilder Builder { get; }
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)