Skip to content

Commit fe0a4ba

Browse files
Support suppressing API version in generated URLs
1 parent 4ceed90 commit fe0a4ba

File tree

3 files changed

+131
-1
lines changed

3 files changed

+131
-1
lines changed

Diff for: src/AspNet/WebApi/src/Asp.Versioning.WebApi/Routing/ApiVersionUrlHelper.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22

3-
namespace Asp.Versioning;
3+
namespace Asp.Versioning.Routing;
44

55
using System.Web.Http.Routing;
66

@@ -32,10 +32,18 @@ public ApiVersionUrlHelper( UrlHelper url )
3232
/// <inheritdoc />
3333
public override string Content( string path ) => Url.Content( path );
3434

35+
/// <inheritdoc />
36+
public override string Link( string routeName, object routeValues ) =>
37+
Url.Link( routeName, AddApiVersionRouteValueIfNecessary( new HttpRouteValueDictionary( routeValues ) ) );
38+
3539
/// <inheritdoc />
3640
public override string Link( string routeName, IDictionary<string, object> routeValues ) =>
3741
Url.Link( routeName, AddApiVersionRouteValueIfNecessary( routeValues ) );
3842

43+
/// <inheritdoc />
44+
public override string Route( string routeName, object routeValues ) =>
45+
Url.Route( routeName, AddApiVersionRouteValueIfNecessary( new HttpRouteValueDictionary( routeValues ) ) );
46+
3947
/// <inheritdoc />
4048
public override string Route( string routeName, IDictionary<string, object> routeValues ) =>
4149
Url.Route( routeName, AddApiVersionRouteValueIfNecessary( routeValues ) );
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace System.Web.Http.Routing;
4+
5+
using Asp.Versioning.Routing;
6+
7+
/// <summary>
8+
/// Provides extension methods for <see cref="UrlHelper"/>.
9+
/// </summary>
10+
public static class UrlHelperExtensions
11+
{
12+
/// <summary>
13+
/// Returns a new URL helper that includes the requested API version.
14+
/// </summary>
15+
/// <param name="urlHelper">The extended <see cref="UrlHelper">URL helper</see>.</param>
16+
/// <returns>A new <see cref="UrlHelper">URL helper</see> that excludes the requested
17+
/// API version or the original <paramref name="urlHelper">URL helper</paramref> if
18+
/// unnecessary.</returns>
19+
/// <remarks>Excluding the requested API version is useful in a limited set of scenarios
20+
/// such as building a URL from an API that versions by URL segment to an API that is
21+
/// version-neutral. A version-neutral API would not use the specified route value and
22+
/// it would be erroneously added as a query string parameter.</remarks>
23+
public static UrlHelper WithoutApiVersion( this UrlHelper urlHelper )
24+
{
25+
if ( urlHelper == null )
26+
{
27+
throw new ArgumentNullException( nameof( urlHelper ) );
28+
}
29+
30+
if ( urlHelper is WithoutApiVersionUrlHelper )
31+
{
32+
return urlHelper;
33+
}
34+
35+
return new WithoutApiVersionUrlHelper( urlHelper );
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
3+
namespace Asp.Versioning.Routing;
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Web.Http.Routing;
8+
9+
internal sealed class WithoutApiVersionUrlHelper : UrlHelper
10+
{
11+
private readonly UrlHelper decorated;
12+
13+
public WithoutApiVersionUrlHelper( UrlHelper decorated ) => this.decorated = decorated;
14+
15+
private ApiVersionRequestProperties Properties => decorated.Request.ApiVersionProperties();
16+
17+
public override string Content( string path )
18+
{
19+
using ( new NoApiVersionScope( Properties ) )
20+
{
21+
return decorated.Content( path );
22+
}
23+
}
24+
25+
public override string Link( string routeName, object routeValues )
26+
{
27+
using ( new NoApiVersionScope( Properties ) )
28+
{
29+
return decorated.Link( routeName, routeValues );
30+
}
31+
}
32+
33+
public override string Link( string routeName, IDictionary<string, object> routeValues )
34+
{
35+
using ( new NoApiVersionScope( Properties ) )
36+
{
37+
return decorated.Link( routeName, routeValues );
38+
}
39+
}
40+
41+
public override string Route( string routeName, object routeValues )
42+
{
43+
using ( new NoApiVersionScope( Properties ) )
44+
{
45+
return decorated.Route( routeName, routeValues );
46+
}
47+
}
48+
49+
public override string Route( string routeName, IDictionary<string, object> routeValues )
50+
{
51+
using ( new NoApiVersionScope( Properties ) )
52+
{
53+
return decorated.Route( routeName, routeValues );
54+
}
55+
}
56+
57+
private sealed class NoApiVersionScope : IDisposable
58+
{
59+
private readonly ApiVersionRequestProperties properties;
60+
private readonly string? rawVersion;
61+
private readonly ApiVersion? version;
62+
private bool disposed;
63+
64+
public NoApiVersionScope( ApiVersionRequestProperties properties )
65+
{
66+
this.properties = properties;
67+
rawVersion = properties.RawRequestedApiVersion;
68+
version = properties.RequestedApiVersion;
69+
properties.RawRequestedApiVersion = default;
70+
properties.RequestedApiVersion = default;
71+
}
72+
73+
public void Dispose()
74+
{
75+
if ( disposed )
76+
{
77+
return;
78+
}
79+
80+
disposed = true;
81+
properties.RawRequestedApiVersion = rawVersion;
82+
properties.RequestedApiVersion = version;
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)