3
3
| Client Ignia, LLC
4
4
| Project Topics Library
5
5
\=============================================================================================================================*/
6
- using OnTopic . AspNetCore . Mvc . Controllers ;
7
- using OnTopic . Internal . Diagnostics ;
6
+ using System ;
8
7
using Microsoft . AspNetCore . Builder ;
9
8
using Microsoft . AspNetCore . Mvc . Infrastructure ;
9
+ using Microsoft . AspNetCore . Mvc . TagHelpers ;
10
10
using Microsoft . AspNetCore . Routing ;
11
11
using Microsoft . Extensions . DependencyInjection ;
12
12
using Microsoft . Extensions . DependencyInjection . Extensions ;
13
+ using OnTopic . AspNetCore . Mvc . Controllers ;
14
+ using OnTopic . Internal . Diagnostics ;
13
15
14
16
namespace OnTopic . AspNetCore . Mvc {
15
17
@@ -38,6 +40,7 @@ public static IMvcBuilder AddTopicSupport(this IMvcBuilder services) {
38
40
| Register services
39
41
\-----------------------------------------------------------------------------------------------------------------------*/
40
42
services . Services . TryAddSingleton < IActionResultExecutor < TopicViewResult > , TopicViewResultExecutor > ( ) ;
43
+ services . Services . TryAddSingleton < TopicRouteValueTransformer > ( ) ;
41
44
42
45
/*------------------------------------------------------------------------------------------------------------------------
43
46
| Configure services
@@ -64,6 +67,12 @@ public static IMvcBuilder AddTopicSupport(this IMvcBuilder services) {
64
67
/// <summary>
65
68
/// Adds an MVC route for handling OnTopic related requests, and maps it to the <see cref="TopicController"/> by default.
66
69
/// </summary>
70
+ /// <remarks>
71
+ /// For ASP.NET Core 3, prefer instead <see cref="MapTopicRoute(IEndpointRouteBuilder, String, String, String)"/>, as
72
+ /// endpoint routing is preferred in ASP.NET Core 3. OnTopic also offers far more extension methods for endpoint routing,
73
+ /// while this method is provided exclusively for backward compatibility.
74
+ /// </remarks>
75
+ [ Obsolete ( "This method is deprecated and will be removed in OnTopic 5. Callers should migrate to endpoint routing." , false ) ]
67
76
public static IRouteBuilder MapTopicRoute (
68
77
this IRouteBuilder routes ,
69
78
string rootTopic ,
@@ -80,12 +89,10 @@ public static IRouteBuilder MapTopicRoute(
80
89
| EXTENSION: MAP TOPIC ROUTE (IENDPOINTROUTEBUILDER)
81
90
\-------------------------------------------------------------------------------------------------------------------------*/
82
91
/// <summary>
83
- /// Adds an MVC route for handling OnTopic related requests, and maps it to the <see cref="TopicController"/> by default.
92
+ /// Adds the <c>{rootTopic}/{**path}</c> endpoint route for a specific root topic, which enables that root to be mapped to
93
+ /// specific topics via the <see cref="TopicRepositoryExtensions.Load(Repositories.ITopicRepository, RouteData)"/>
94
+ /// extension method used by <see cref="TopicController"/>.
84
95
/// </summary>
85
- /// <remarks>
86
- /// This is functionally identical to <see cref="MapTopicRoute(IRouteBuilder, String, String, String)"/>, except that it
87
- /// targets the <see cref="IEndpointRouteBuilder"/>, which is preferred in ASP.NET Core 3.
88
- /// </remarks>
89
96
public static ControllerActionEndpointConventionBuilder MapTopicRoute (
90
97
this IEndpointRouteBuilder routes ,
91
98
string rootTopic ,
@@ -94,10 +101,133 @@ public static ControllerActionEndpointConventionBuilder MapTopicRoute(
94
101
) =>
95
102
routes . MapControllerRoute (
96
103
name : $ "{ rootTopic } Topic",
97
- pattern : rootTopic + "/{*path}" ,
104
+ pattern : rootTopic + "/{** path}" ,
98
105
defaults : new { controller , action , rootTopic }
99
106
) ;
100
107
108
+ /*==========================================================================================================================
109
+ | EXTENSION: MAP TOPIC AREA ROUTE (IENDPOINTROUTEBUILDER)
110
+ \-------------------------------------------------------------------------------------------------------------------------*/
111
+ /// <summary>
112
+ /// Adds the <c>{areaName}/{**path}</c> endpoint route for a specific area, which enables the areas to be mapped to
113
+ /// specific topics via the <see cref="TopicRepositoryExtensions.Load(Repositories.ITopicRepository, RouteData)"/>
114
+ /// extension method used by <see cref="TopicController"/>.
115
+ /// </summary>
116
+ /// <remarks>
117
+ /// If there are multiple routes that fit this description, you can instead opt to use the <see cref=
118
+ /// "MapTopicAreaRoute(IEndpointRouteBuilder)"/> extension, which will register all areas.
119
+ /// </remarks>
120
+ public static ControllerActionEndpointConventionBuilder MapTopicAreaRoute (
121
+ this IEndpointRouteBuilder routes ,
122
+ string areaName ,
123
+ string ? controller = null ,
124
+ string action = "Index"
125
+ ) =>
126
+ routes . MapAreaControllerRoute (
127
+ name : $ "TopicAreas",
128
+ areaName : areaName ,
129
+ pattern : areaName + "/{**path}" ,
130
+ defaults : new { controller = controller ?? areaName , action , rootTopic = areaName }
131
+ ) ;
132
+
133
+ /// <summary>
134
+ /// Adds the <c>{area:exists}/{**path}</c> endpoint route for all areas, which enables the areas to be mapped to specific
135
+ /// topics via the <see cref="TopicRepositoryExtensions.Load(Repositories.ITopicRepository, RouteData)"/> extension method
136
+ /// used by <see cref="TopicController"/>.
137
+ /// </summary>
138
+ /// <remarks>
139
+ /// Be aware that this method uses the <see cref="ControllerEndpointRouteBuilderExtensions.MapDynamicControllerRoute{
140
+ /// TTransformer}(IEndpointRouteBuilder, String)"/> method. In .NET 3.x, this is incompatible with both the <see cref=
141
+ /// "AnchorTagHelper"/> and <see cref="LinkGenerator"/> classes. This means that e.g. <c>@Url.Action()</c> references
142
+ /// in views won't be properly formed. If these are required, prefer registering each route individually using <see cref=
143
+ /// "MapTopicAreaRoute(IEndpointRouteBuilder, String, String?, String)"/>.
144
+ /// </remarks>
145
+ public static void MapTopicAreaRoute ( this IEndpointRouteBuilder routes ) =>
146
+ routes . MapDynamicControllerRoute < TopicRouteValueTransformer > ( "{area:exists}/{**path}" ) ;
147
+
148
+ /*==========================================================================================================================
149
+ | EXTENSION: MAP DEFAULT AREA CONTROLLER ROUTES (IENDPOINTROUTEBUILDER)
150
+ \-------------------------------------------------------------------------------------------------------------------------*/
151
+ /// <summary>
152
+ /// Adds the fully-qualified <c>{area:exists}/{controller}/{action=Index}/{id?}</c> endpoint route for all areas.
153
+ /// </summary>
154
+ /// <remarks>
155
+ /// This is analogous to the standard <see cref="ControllerEndpointRouteBuilderExtensions.MapDefaultControllerRoute(
156
+ /// IEndpointRouteBuilder)"/> method that ships with ASP.NET, except that it works with areas.
157
+ /// </remarks>
158
+ public static void MapDefaultAreaControllerRoute ( this IEndpointRouteBuilder routes ) =>
159
+ routes . MapControllerRoute (
160
+ name : "TopicAreas" ,
161
+ pattern : "{area:exists}/{controller}/{action=Index}/{id?}"
162
+ ) ;
163
+
164
+ /*==========================================================================================================================
165
+ | EXTENSION: MAP IMPLICIT AREA CONTROLLER ROUTES (IENDPOINTROUTEBUILDER)
166
+ \-------------------------------------------------------------------------------------------------------------------------*/
167
+ /// <summary>
168
+ /// Adds the <c>{areaName}/{action=Index}</c> endpoint route for a specific area where the controller has the same name as
169
+ /// the area.
170
+ /// </summary>
171
+ /// <remarks>
172
+ /// <para>
173
+ /// This extension method implicitly assigns the controller name based on the area name. This is advantageous when an
174
+ /// area has a single controller which is named after the area—e.g., <c>[Area("Forms")]</c> and <c>FormsController</c>—
175
+ /// as this allows the redundant <c>Controller</c> to be ommited from the route (e.g., <c>/Forms/Forms/{action}</c>.
176
+ /// </para>
177
+ /// <para>
178
+ /// If there are multiple routes that fit this description, you can instead opt to use the <see cref=
179
+ /// "MapImplicitAreaControllerRoute(IEndpointRouteBuilder)"/> overload, which will register all areas.
180
+ /// </para>
181
+ /// </remarks>
182
+ public static void MapImplicitAreaControllerRoute ( this IEndpointRouteBuilder routes , string areaName ) =>
183
+ routes . MapAreaControllerRoute (
184
+ name : $ "{ areaName } TopicArea",
185
+ areaName : areaName ,
186
+ pattern : $ "{ areaName } /{{action}}",
187
+ defaults : new { controller = areaName }
188
+ ) ;
189
+
190
+ /// <summary>
191
+ /// Adds the <c>{area:exists}/{action=Index}</c> endpoint route for all areas where the controller has the same name as
192
+ /// the area.
193
+ /// </summary>
194
+ /// <remarks>
195
+ /// <para>
196
+ /// This extension method implicitly assigns the controller name based on the area name. This is advantageous when there
197
+ /// are multiple areas which have a single controller which is named after the area—e.g., <c>[Area("Forms")]</c> and
198
+ /// <c>FormsController: Controller</c>—as this allows those to be collectively registered under a single route, without
199
+ /// needing the redundant <c>Controller</c> value to be defined in the route (e.g., <c>/Forms/Forms/{action}</c>.
200
+ /// </para>
201
+ /// <para>
202
+ /// Be aware that this method uses the <see cref="ControllerEndpointRouteBuilderExtensions.MapDynamicControllerRoute{
203
+ /// TTransformer}(IEndpointRouteBuilder, String)"/> method. In .NET 3.x, this is incompatible with both the <see cref=
204
+ /// "AnchorTagHelper"/> and <see cref="LinkGenerator"/> classes. This means that e.g. <c>@Url.Action()</c> references
205
+ /// in views won't be properly formed. If these are required, prefer registering each route individually using <see
206
+ /// cref="MapImplicitAreaControllerRoute(IEndpointRouteBuilder, String)"/>.
207
+ /// </para>
208
+ /// </remarks>
209
+ public static void MapImplicitAreaControllerRoute ( this IEndpointRouteBuilder routes ) =>
210
+ routes . MapDynamicControllerRoute < TopicRouteValueTransformer > ( "{area:exists}/{action=Index}" ) ;
211
+
212
+ /*==========================================================================================================================
213
+ | EXTENSION: MAP TOPIC SITEMAP (IENDPOINTROUTEBUILDER)
214
+ \-------------------------------------------------------------------------------------------------------------------------*/
215
+ /// <summary>
216
+ /// Adds the <c>Sitemap/{action=Index}</c> endpoint route for the OnTopic sitemap.
217
+ /// </summary>
218
+ /// <remarks>
219
+ /// For most implementations, this will be covered by the default route, such as that implemented by the standard <see
220
+ /// cref="ControllerEndpointRouteBuilderExtensions.MapDefaultControllerRoute(IEndpointRouteBuilder)"/> method that ships
221
+ /// with ASP.NET. This extension method is provided as a convenience method for implementations that aren't using the
222
+ /// standard route, for whatever reason, and want a specific route setup for the sitemap.
223
+ /// </remarks>
224
+ public static ControllerActionEndpointConventionBuilder MapTopicSitemap ( this IEndpointRouteBuilder routes ) =>
225
+ routes . MapControllerRoute (
226
+ name : "TopicSitemap" ,
227
+ pattern : "Sitemap/{action=Index}" ,
228
+ defaults : new { controller = "Sitemap" }
229
+ ) ;
230
+
101
231
/*==========================================================================================================================
102
232
| EXTENSION: MAP TOPIC REDIRECT (IENDPOINTROUTEBUILDER)
103
233
\-------------------------------------------------------------------------------------------------------------------------*/
0 commit comments