Skip to content

Commit 93ba673

Browse files
Chris Martinezcommonsensesoftware
Chris Martinez
authored andcommitted
Fix route name lookup when hosted in IIS. Fixes #302.
1 parent 2dff7b8 commit 93ba673

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

src/Microsoft.AspNet.OData.Versioning.ApiExplorer/Microsoft.AspNet.OData.Versioning.ApiExplorer.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<VersionPrefix>1.2.1</VersionPrefix>
4+
<VersionPrefix>1.2.2</VersionPrefix>
55
<AssemblyVersion>1.2.0.0</AssemblyVersion>
66
<TargetFramework>net45</TargetFramework>
77
<AssemblyTitle>Microsoft ASP.NET Web API Versioned API Explorer for OData v4.0</AssemblyTitle>
@@ -12,7 +12,7 @@
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15-
<ReleaseNotes Include="Fix convention-based link generation (Issue 265)" />
15+
<ReleaseNotes Include="Fix hosting in IIS (Issue 302)" />
1616
</ItemGroup>
1717

1818
<ItemGroup>

src/Microsoft.AspNet.OData.Versioning.ApiExplorer/System.Web.Http/HttpRouteCollectionExtensions.cs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
{
33
using System.Collections.Generic;
44
using System.Diagnostics.Contracts;
5+
using System.Reflection;
56
using System.Web.Http.Routing;
7+
using static System.Reflection.BindingFlags;
68

79
static class HttpRouteCollectionExtensions
810
{
@@ -11,9 +13,7 @@ internal static string GetRouteName( this HttpRouteCollection routes, IHttpRoute
1113
Contract.Requires( routes != null );
1214
Contract.Requires( route != null );
1315

14-
var items = new KeyValuePair<string, IHttpRoute>[routes.Count];
15-
16-
routes.CopyTo( items, 0 );
16+
var items = CopyRouteEntries( routes );
1717

1818
foreach ( var item in items )
1919
{
@@ -25,5 +25,61 @@ internal static string GetRouteName( this HttpRouteCollection routes, IHttpRoute
2525

2626
return null;
2727
}
28+
29+
static KeyValuePair<string, IHttpRoute>[] CopyRouteEntries( HttpRouteCollection routes )
30+
{
31+
Contract.Requires( routes != null );
32+
Contract.Ensures( Contract.Result<KeyValuePair<string, IHttpRoute>[]>() != null );
33+
34+
var items = new KeyValuePair<string, IHttpRoute>[routes.Count];
35+
36+
try
37+
{
38+
routes.CopyTo( items, 0 );
39+
}
40+
catch ( NotSupportedException ) when ( routes.GetType().FullName == "System.Web.Http.WebHost.Routing.HostedHttpRouteCollection" )
41+
{
42+
var keys = GetRouteKeys( routes );
43+
44+
for ( var i = 0; i < keys.Count; i++ )
45+
{
46+
var key = keys[i];
47+
var route = routes[key];
48+
49+
items[i] = new KeyValuePair<string, IHttpRoute>( key, route );
50+
}
51+
}
52+
53+
return items;
54+
}
55+
56+
static IReadOnlyList<string> GetRouteKeys( HttpRouteCollection routes )
57+
{
58+
Contract.Requires( routes != null );
59+
Contract.Ensures( Contract.Result<IReadOnlyList<string>>() != null );
60+
61+
var collection = GetKeys( routes );
62+
var keys = new string[collection.Count];
63+
64+
collection.CopyTo( keys, 0 );
65+
66+
return keys;
67+
}
68+
69+
static ICollection<string> GetKeys( HttpRouteCollection routes )
70+
{
71+
Contract.Requires( routes != null );
72+
Contract.Ensures( Contract.Result<ICollection<string>>() != null );
73+
74+
// HACK: System.Web.Routing.RouteCollection doesn't expose the names associated with registered routes. The
75+
// HostedHttpRouteCollection could have provided an adapter to support it, but didn't. Instead, it always throws
76+
// NotSupportedException for the HttpRouteCollection.CopyTo method. This only happens when hosted on IIS. The
77+
// only way to get the keys is use reflection to poke at the underlying dictionary.
78+
var routeCollection = routes.GetType().GetField( "_routeCollection", Instance | NonPublic ).GetValue( routes );
79+
var dictionary = routeCollection.GetType().GetField( "_namedMap", Instance | NonPublic ).GetValue( routeCollection );
80+
var keys = (ICollection<string>) dictionary.GetType().GetRuntimeProperty( "Keys" ).GetValue( dictionary, null );
81+
82+
return keys;
83+
}
2884
}
2985
}

0 commit comments

Comments
 (0)