Why do you need to compare them? You can always render the canonical URL.
@Html.CanonicalLink() or any other canonical link functional generates a URL from the content reference. Let's take an example of news partial routing example from Developer documentation
In the example, the part of the URL that is http://site/News/ is the URL to a page instance of model type NewsContainer. By registering a partial router for type NewsContainer, the partial router routes the remaining part of the URL. The partial router handles routing Sports/TheGame/.
public class NewsPartialRouter : IPartialRouter<NewsContainer, NewsContent>
If I am on the URL http://site/News/Sports/TheGame/. the @Html.CanonicalLink() always output http://site/News/ instead of http://site/News/Sports/TheGame/
Hi Rich
We encountered the similar issue recently while using CanonicalLink html helper with Partial router. Our naive solution is to create a custom canonical url property and populated it's value when the current content's type is the specific type used in partial router, then render canonical url with this custom property in the layout instead of CanonicalLink.
e.g.
If (xxxPage is NewsContent) { customurl = "<get current request url from Request object>"}
In razor layout
@if(customurl has value) {// render canonical with customurl} else{@Html.CanonicalLink()}
I hope above helps.
The URL Resolver should not cause a stack overflow. There must be an infinite loop in your partial router code that causes that. I just did a quick test with a partial router like this, and re-used the Standard Page view in the Alloy templates:
public class RoutedPartialObject
{
public string Category { get; set; }
public string Value { get; set; }
}
public class PartialRouter : IPartialRouter<StandardPage, RoutedPartialObject>
{
// Store in an option and load during configuration.
private static readonly ContentReference Root = new(11353);
public PartialRouteData GetPartialVirtualPath(RoutedPartialObject content, UrlGeneratorContext urlGeneratorContext)
{
return new PartialRouteData()
{
BasePathRoot = Root,
PartialVirtualPath = $"{content.Category}/{content.Value}"
};
}
public object RoutePartial(StandardPage content, UrlResolverContext segmentContext)
{
var counter = 0;
var category = "";
var value = "";
// GetNextSegment should typically be called in a loop until
// the segmentContext.RemainingSegments is empty, or everything
// needed for this partial router has been extracted. Then update
// if there is anything remaining and return the partial object.
while (!segmentContext.RemainingSegments.IsEmpty)
{
var segment = segmentContext.GetNextSegment();
if (counter == 0)
{
category = segment.Next.ToString();
}
else if (counter == 1)
{
value = segment.Next.ToString();
}
else
{
// In this example we don't support more than two segments.
segmentContext.RemainingSegments = null;
}
// Update what we have consumed.
segmentContext.RemainingSegments = segment.Remaining;
counter++;
}
return new RoutedPartialObject
{
Category = category,
Value = value,
};
}
}
public class RoutedPartialObjectController : Controller, IRenderTemplate<RoutedPartialObject>
{
public ActionResult Index(StandardPage content)
{
var model = new PageViewModel<StandardPage>(content);
var routedObject = HttpContext.Features.Get<IContentRouteFeature>()
.RoutedContentData
.PartialRoutedObject as RoutedPartialObject;
ViewData["RoutedPartialObject"] = routedObject;
return View("~/Views/StandardPage/Index.cshtml", model);
}
}
Calling any method on the URL Resolver with this code does work.
The @Html.CanonicalLink() tag helper does not support partial routing unfortunately. As Vincent has suggested, you can render the link manually for the partially routed object instead. I will however add this as a feature request, because we should support this.
Hi Rich,
One approach to generating a canonical link for a partial router is to analyze the Request.Path string URL to determine if it belongs to a partial router. You can implement custom logic by parsing the URL and checking for distinctive markers that indicate a partial route.
As a helpful resource, you could look at the SEOBOOST library for Optimizely, which offers functionality for optimizing SEO-related aspects. Check out the GitHub repository here: https://github.com/adnanzameer/optimizely-seoboost
Feel free to explore the library's documentation and see if it aligns with your requirements.
Easiest is probably to check if the current HTTP Context has a partial routed object:
var routedObject = HttpContext.Features.Get<IContentRouteFeature>()
.RoutedContentData
.PartialRoutedObject as RoutedPartialObject;
Then generate the URL for this object:
var urlResolver = HttpContext.RequestServices.GetRequiredService<UrlResolver>();
var url = urlResolver.GetVirtualPathForNonContent(
routedObject,
"the-requested-language",
new()
{
ForceCanonical = true,
ForceAbsolute = true
});
And finally compare this URL with the requested URL.
I'm attempting to generate a canonical link for a partial router. How can I determine if the Request.Path string URL belong to a partial router? Is there a default and straightforward method for achieving this?