33| Client Ignia, LLC
44| Project Topics Library
55\=============================================================================================================================*/
6- using OnTopic . AspNetCore . Mvc . Controllers ;
7- using OnTopic . Internal . Diagnostics ;
6+ using System ;
87using Microsoft . AspNetCore . Builder ;
98using Microsoft . AspNetCore . Mvc . Infrastructure ;
9+ using Microsoft . AspNetCore . Mvc . TagHelpers ;
1010using Microsoft . AspNetCore . Routing ;
1111using Microsoft . Extensions . DependencyInjection ;
1212using Microsoft . Extensions . DependencyInjection . Extensions ;
13+ using OnTopic . AspNetCore . Mvc . Controllers ;
14+ using OnTopic . Internal . Diagnostics ;
1315
1416namespace OnTopic . AspNetCore . Mvc {
1517
@@ -38,6 +40,7 @@ public static IMvcBuilder AddTopicSupport(this IMvcBuilder services) {
3840 | Register services
3941 \-----------------------------------------------------------------------------------------------------------------------*/
4042 services . Services . TryAddSingleton < IActionResultExecutor < TopicViewResult > , TopicViewResultExecutor > ( ) ;
43+ services . Services . TryAddSingleton < TopicRouteValueTransformer > ( ) ;
4144
4245 /*------------------------------------------------------------------------------------------------------------------------
4346 | Configure services
@@ -64,6 +67,12 @@ public static IMvcBuilder AddTopicSupport(this IMvcBuilder services) {
6467 /// <summary>
6568 /// Adds an MVC route for handling OnTopic related requests, and maps it to the <see cref="TopicController"/> by default.
6669 /// </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 ) ]
6776 public static IRouteBuilder MapTopicRoute (
6877 this IRouteBuilder routes ,
6978 string rootTopic ,
@@ -80,12 +89,10 @@ public static IRouteBuilder MapTopicRoute(
8089 | EXTENSION: MAP TOPIC ROUTE (IENDPOINTROUTEBUILDER)
8190 \-------------------------------------------------------------------------------------------------------------------------*/
8291 /// <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"/>.
8495 /// </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>
8996 public static ControllerActionEndpointConventionBuilder MapTopicRoute (
9097 this IEndpointRouteBuilder routes ,
9198 string rootTopic ,
@@ -94,10 +101,133 @@ public static ControllerActionEndpointConventionBuilder MapTopicRoute(
94101 ) =>
95102 routes . MapControllerRoute (
96103 name : $ "{ rootTopic } Topic",
97- pattern : rootTopic + "/{*path}" ,
104+ pattern : rootTopic + "/{** path}" ,
98105 defaults : new { controller , action , rootTopic }
99106 ) ;
100107
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+
101231 /*==========================================================================================================================
102232 | EXTENSION: MAP TOPIC REDIRECT (IENDPOINTROUTEBUILDER)
103233 \-------------------------------------------------------------------------------------------------------------------------*/
0 commit comments