I think in CMS 12 you have a simpler option available to you. In the configure method of your startup class you should have a call to endpoints.MapContent(). There's an extension method you can call on that called "MapTemplate" which allows you to register a custom route pattern for your controller which you could call like this:
app.UseEndpoints(endpoints =>
{
endpoints.MapContent()
.MapTemplate<BlogListPageController>("{page}");
});
You then shouldn't need the partial router at all.
Paul,
Prior to adding this issue, I tried and I got an error (see below)
app.UseEndpoints(endpoints =>
{
endpoints.MapContent()
.MapTemplate<BlogListPageController>("{action}/{page:int}");
});
then based on your reply, I just tried
app.UseEndpoints(endpoints =>
{
endpoints.MapContent()
.MapTemplate<BlogListPageController>("{page:int}");
endpoints.MapControllers();
endpoints.MapRazorPages();
}
and
app.UseEndpoints(endpoints =>
{
endpoints.MapContent()
.MapTemplate<BlogListPageController>("{page}");
endpoints.MapControllers();
endpoints.MapRazorPages();
}
But I'm getting this error when going to /blog/3 which is the same error I got when I included the action in the pattern
ArgumentNullException: Value cannot be null. (Parameter 'propertyName')
EPiServer.Framework.Validator.ThrowIfNullOrEmpty(string name, string value)
EPiServer.Web.Internal.BlobResolver.ResolveProperty(IContentData content, string propertyName)
EPiServer.Core.Routing.Internal.BlobPartialRouter.RoutePartial(IContent content, UrlResolverContext segmentContext)
EPiServer.Core.Routing.PartialRouter<TIncoming, TOutgoing>.RoutePartial(IContent content, UrlResolverContext urlResolverContext)
EPiServer.Core.Routing.Pipeline.Internal.PartialUrlResolverPipelineStep.Resolve(UrlResolverContext context, UrlResolverOptions options)
EPiServer.Core.Routing.Internal.DefaultContentUrlResolver.Resolve(Uri url, UrlResolverOptions options)
EPiServer.Web.Routing.Internal.PipelineUrlResolver.Route(UrlBuilder urlBuilder, RouteArguments routeArguments)
EPiServer.Web.Routing.Matching.Internal.ContentMatcherPolicy.MapEndpointAsync(Endpoint originalEndpoint, HttpContext httpContext)
EPiServer.Web.Routing.Matching.Internal.ContentMatcherPolicy.ApplyAsync(HttpContext httpContext, CandidateSet candidates)
Microsoft.AspNetCore.Routing.Matching.DfaMatcher.SelectEndpointWithPoliciesAsync(HttpContext httpContext, IEndpointSelectorPolicy[] policies, CandidateSet candidateSet)
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatch|8_1(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task matchTask)
SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Looking at that error, I wonder whether there's a route already registered which is being a bit over zealous in what it's handling. It looks like the request is being processed by SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware which has presumably spotted the integer at the end of the URL and assumed it's an image dimension.
If it is that, maybe try changing the route pattern to something like this:
MapTemplate<BlogListPageController>("p{page:int}/")
then, rather than /blog/3 it would be /blog/p3
I disabled the SixeLabors code and I still get an error. I tried tried:
endpoints.MapContent()
.MapTemplate<BlogListPageController>("{action}/p{page:int}");
endpoints.MapContent()
.MapTemplate<BlogListPageController>("{action}/{page:int}");
endpoints.MapContent()
.MapTemplate<BlogListPageController>("{page:int}");
Error:
ArgumentNullException: Value cannot be null. (Parameter 'propertyName')
EPiServer.Framework.Validator.ThrowIfNullOrEmpty(string name, string value)
EPiServer.Web.Internal.BlobResolver.ResolveProperty(IContentData content, string propertyName)
EPiServer.Core.Routing.Internal.BlobPartialRouter.RoutePartial(IContent content, UrlResolverContext segmentContext)
EPiServer.Core.Routing.PartialRouter<TIncoming, TOutgoing>.RoutePartial(IContent content, UrlResolverContext urlResolverContext)
EPiServer.Core.Routing.Pipeline.Internal.PartialUrlResolverPipelineStep.Resolve(UrlResolverContext context, UrlResolverOptions options)
EPiServer.Core.Routing.Internal.DefaultContentUrlResolver.Resolve(Uri url, UrlResolverOptions options)
EPiServer.Web.Routing.Internal.PipelineUrlResolver.Route(UrlBuilder urlBuilder, RouteArguments routeArguments)
EPiServer.Web.Routing.Matching.Internal.ContentMatcherPolicy.MapEndpointAsync(Endpoint originalEndpoint, HttpContext httpContext)
EPiServer.Web.Routing.Matching.Internal.ContentMatcherPolicy.ApplyAsync(HttpContext httpContext, CandidateSet candidates)
Microsoft.AspNetCore.Routing.Matching.DfaMatcher.SelectEndpointWithPoliciesAsync(HttpContext httpContext, IEndpointSelectorPolicy[] policies, CandidateSet candidateSet)
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatch|8_1(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task matchTask)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
NOTE: One of the reason I was going down the path of using IPartialRouter was so the Canonical URL will be correct and include the page number (not yet implemented in code).
I added a note, but to close this out, the issue was that page is a reserved word, so we used pageNum.
In Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapContent()
// pagination routing
.MapTemplate<BlogListPageController>("{pageNum:int}");
});
}
In BlogListPageController.cs:
public ActionResult Index(BlogListPage currentPage, int? pageNum = 1)
{
var model = new BlogListPageViewModel(currentPage);
return View(PopulateViewModel(model, pageNum ?? 1));
}
I have a page type of BlogListPage with a controller:
I am able to call this page: /blog and /blog?page=3, but I want to be able to call page 3 using this url: /blog/3
I have implemented a Partial Route and registed it
When I run and set breakpoints and call /blog/3, BlogPaginationPartialRouting.RoutePartial() is hit and the page value is set. And the the controller Index action is hit, but the page parameter is set to the default of 1 and not to 3.
How can I set the action parameter for the page value in the IPartialRouter?
I found this https://world.optimizely.com/forum/developer-forum/CMS/Thread-Container/2017/3/custom-routing-with-extra-parameters-in-action-method post, but it is for older version.