Modify Umbraco 8 URLs with the UrlProvider and ContentFinder
Hi,
One of my final tasks in converting our Umbraco 7 build to Umbraco 8 is to remove the category from our guide links. For example: website/guide/this-category/this-article becomes website/guide/this-article.
On our Umbraco 7 built I used the following tutorial to get this working:
https://24days.in/umbraco-cms/2014/urlprovider-and-contentfinder
Now, I am trying to convert this to Umbraco 8.
I have used the following code to register the classes at start up:
Content UrlProvider:
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class UrlProviderStartUp : IUserComposer
{
public void Compose(Composition composition)
{
composition.UrlProviders().InsertBefore<DefaultUrlProvider, GuideUrlProvider>();
}
}
Content finder:
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class ContentFinderStartUp : IUserComposer
{
public void Compose(Composition composition)
{
composition.ContentFinders().InsertBefore<ContentFinderByUrl, GuideContentFinder>();
}
}
First of all here is my Umbraco 8 code for the UrlProvider, which is causing the biggest issue, Umbraco now uses UrlInfo
public class GuideUrlProvider : BaseClass, IUrlProvider
{
public IEnumerable<UrlInfo> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
{
return Enumerable.Empty<UrlInfo>();
}
public UrlInfo GetUrl(UmbracoContext umbracoContext, IPublishedContent content, UrlMode mode, string culture, Uri current)
{
try
{
var contentUrl = umbracoContext.Content.GetById(content.Id);
if (contentUrl != null && content.ContentType.Alias == "guideArticle" && content.Parent != null && content.Parent.Parent.Name == "Buy to let guide")
{
// code to remove CATEGORY section of url
if (content.Parent.ContentType.Alias == "guidesIndex")
{
var url = string.Empty;
//this will remove the category name from the guide url
var path = content.Parent.Url;
var parts = path.Split(new[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries);
UrlInfo urll = "/" + parts[0] + "/" + content.Url + "/";
return urll;
}
}
}
catch { }
return null;
}
}
The line : UrlInfo urll = "/" + parts[0] + "/" + content.Url + "/";
Cannot convert string to Umbraco.Web.Routing.UrlInfo and UrlInfo says its read only.
Any assistance in converting this to Umbraco 8 would be appreciated.
HI,
Thank you for your reply.
I have implemented this, but now have come across a bigger problem.
The updated code get stuck in a loop and I get a StackOverflowException, it crashes the whole application, so at the moment I don't know of a way to implement what was done on Umbraco 7 using the tutorial above.
I suspect when inside your UrlProvider, when you make the call to content.Url ... this will in fact call the registered UrlProviders in turn to determine the Url, and therefore cyclically calling the same UrlProvider over and over!
This is where the strategy of inheriting from the DefaultUrlProvider can be advantageous, as you can call the base.GetUrl() method on the DefaultUrlProvider to get the 'Url' that 'would have been generated' had your new provider not been put in place... and that avoids cyclically calling the same provider over and over...
public class GuideUrlProvider : DefaultUrlProvider
{
public GuideUrlProvider(IRequestHandlerSection requestSettings, ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper) : base(requestSettings,logger,globalSettings,siteDomainHelper)
{ }
public override IEnumerable<UrlInfo> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
{
// manipulate 'other' urls if required, these appear in backoffice in addition to the main url for the item
return base.GetOtherUrls(umbracoContext, id, current);
}
public override UrlInfo GetUrl(UmbracoContext umbracoContext, IPublishedContent content, UrlMode mode, string culture, Uri current)
{
{
if (content != null && content.ContentType.Alias == "guideArticle"){
// content.Level will give you the depth of the item in the tree
// content.Path will give you ids of parent items, if this should only work in a certain section of the site (if you can avoid traversing with Parent.Parent etc this will be more efficient)
try
{
// code to remove CATEGORY section of url
// Can articles be created anywhere other than under Guide Index pages?
// could content.Level or content.Path be used instead?
//if (content.Parent.ContentType.Alias == "guidesIndex")
{
var url = string.Empty;
//this will remove the category name from the guide url
// I'm not sure of your logic here, based on your content tree.. but do what you have to do!//
// but use
var parentUrlInfo = base.GetUrl(umbracoContext, content,Parent, mode, culture,current);
var defaultUrlInfo = base.GetUrl(umbracoContext, content, mode, culture,current);
// and you can use IsUrl to detect whether item is published, if not published then the Url will be a text message instead of a url!
if (!defaultUrlInfo.IsUrl){
return defaultUrlInfo;
}
string defaultUrl = defaultUrlInfo.Text;
string parentUrl = parentUrlInfo.Text;
string yourNewUrlAfterMessingAroundWithSegments;
return return new UrlInfo(yourNewUrlAfterMessingAroundWithSegments, true,defaultUrlInfo.Culture);
}
}
}
catch {
//log error? return default provider?
return base.GetUrl(umbracoContext, content, mode, culture, current);
}
return base.GetUrl(umbracoContext, content, mode, culture, current);
}
}
or at least that is the gist, to avoid calling itself...
Modify Umbraco 8 URLs with the UrlProvider and ContentFinder
Hi, One of my final tasks in converting our Umbraco 7 build to Umbraco 8 is to remove the category from our guide links. For example: website/guide/this-category/this-article becomes website/guide/this-article. On our Umbraco 7 built I used the following tutorial to get this working: https://24days.in/umbraco-cms/2014/urlprovider-and-contentfinder
Now, I am trying to convert this to Umbraco 8.
I have used the following code to register the classes at start up:
Content UrlProvider:
Content finder:
First of all here is my Umbraco 8 code for the UrlProvider, which is causing the biggest issue, Umbraco now uses UrlInfo
The line : UrlInfo urll = "/" + parts[0] + "/" + content.Url + "/"; Cannot convert string to Umbraco.Web.Routing.UrlInfo and UrlInfo says its read only.
Any assistance in converting this to Umbraco 8 would be appreciated.
Thank you,
Pete
Hi Pete
Would you return a new instance of the UrlInfo class?
This example in the docs seems to suggest you can...?
https://our.umbraco.com/Documentation/Reference/Routing/Request-Pipeline/outbound-pipeline-vpre81#example-1
return new UrlInfo("/" + parts[0] + "/" + content.Url + "/", true,defaultUrlInfo.Culture);
although the example seems to suggest that a good strategy is to inherit from the DefaultUrlProvider, and override the abstract GetUrl method...
... anyway I reckon you can just new up a UrlInfo class to return!
regards
Marc
HI, Thank you for your reply. I have implemented this, but now have come across a bigger problem. The updated code get stuck in a loop and I get a StackOverflowException, it crashes the whole application, so at the moment I don't know of a way to implement what was done on Umbraco 7 using the tutorial above.
Hi Peter
I suspect when inside your UrlProvider, when you make the call to content.Url ... this will in fact call the registered UrlProviders in turn to determine the Url, and therefore cyclically calling the same UrlProvider over and over!
This is where the strategy of inheriting from the DefaultUrlProvider can be advantageous, as you can call the base.GetUrl() method on the DefaultUrlProvider to get the 'Url' that 'would have been generated' had your new provider not been put in place... and that avoids cyclically calling the same provider over and over...
or at least that is the gist, to avoid calling itself...
regards
marc
is working on a reply...