We have recently performed a Sitecore upgrade for one of our clients up to Sitecore 9.3 and have noticed that there are changes to link generation functionality.
Before Sitecore 9.3 the normal way of getting the Item Url using custom options would be
var options = LinkManager.GetDefaultUrlOptions(); // set new values to options... var url = LinkManager.GetItemUrl(item, options);
Starting from version 9.3, the class Sitecore.Links.UrlOptions becomes obsolete as well as all methods that use it.
Instead, the proper way of doing the same would look like this:
var options = LinkManager.GetDefaultUrlBuilderOptions(); // set new values to options... var url = LinkManager.GetItemUrl(item, options);
There is already a documentation available here for this change.
Therefore we can find a new object in the configuration:
<links> <urlBuilder> <alwaysIncludeServerUrl>false</alwaysIncludeServerUrl> <languageEmbedding>asNeeded</languageEmbedding> <languageLocation>filePath</languageLocation> <lowercaseUrls>false</lowercaseUrls> <encodeNames>true</encodeNames> <useDisplayName>false</useDisplayName> </urlBuilder> </links>
In addition to that we have two classes that re-use given object:
<links> <itemUrlBuilder type="Sitecore.Links.UrlBuilders.ItemUrlBuilder, Sitecore.Kernel"> <param type="Sitecore.Links.UrlBuilders.DefaultItemUrlBuilderOptions, Sitecore.Kernel" desc="defaultOptions"> <alwaysIncludeServerUrl ref="links/urlBuilder/alwaysIncludeServerUrl"/> <languageEmbedding ref="links/urlBuilder/languageEmbedding"/> <languageLocation ref="links/urlBuilder/languageLocation"/> <lowercaseUrls ref="links/urlBuilder/lowercaseUrls"/> <encodeNames ref="links/urlBuilder/encodeNames"/> <useDisplayName ref="links/urlBuilder/useDisplayName"/> <addAspxExtension>false</addAspxExtension> <siteResolving>true</siteResolving> <shortenUrls>true</shortenUrls> </param> </itemUrlBuilder> <mediaUrlBuilder type="Sitecore.Links.UrlBuilders.MediaUrlBuilder, Sitecore.Kernel"> <param type="Sitecore.Links.UrlBuilders.DefaultMediaUrlBuilderOptions, Sitecore.Kernel" desc="defaultOptions"> <alwaysIncludeServerUrl ref="links/urlBuilder/alwaysIncludeServerUrl"/> <languageEmbedding ref="links/urlBuilder/languageEmbedding"/> <languageLocation ref="links/urlBuilder/languageLocation"/> <lowercaseUrls ref="links/urlBuilder/lowercaseUrls"/> <encodeNames ref="links/urlBuilder/encodeNames"/> <useDisplayName ref="links/urlBuilder/useDisplayName"/> <absolutePath>true</absolutePath> <includeExtension>true</includeExtension> </param> <param desc="mediaLinkPrefix">$(1)</param> </mediaUrlBuilder> </links>
It applears that now we can have two different patterns for URL generation for Sitecore items and Sitecore media by configuring different values to each URL builder.
By the way, all those properties look familiar right?
Of course, we have been using those a million times because many solutions we worked with have a customized link provider or the default url options that are being patched in the project by patching the inself in the config.
So how do we patch the default url options now? It seems that Sitecore wants us to be patching the links/urlBuilder config node now instead the way we used to:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <links> <urlBuilder> <languageEmbedding>never</languageEmbedding> <lowercaseUrls>true</lowercaseUrls> </urlBuilder> </links> </sitecore> </configuration>
Would the old good way of patching still work?
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <linkManager defaultProvider="sitecore"> <providers> <add name="sitecore"> <patch:attribute name="languageEmbedding">never</patch:attribute> <patch:attribute name="lowercaseUrls">true</patch:attribute> </add> </providers> </linkManager> </sitecore> </configuration>
Yes, patching the default link provider overrides the new links/urlBuilder config node, however I would stick to the new way of doing that in order to reduce the technical debt.
But wait, there is still a confusion left… Back in the version 6 days we had old good static class Sitecore.Links.LinkManager and everything worked fine. Then Sitecore introduced abstractions and there appeared a new class Sitecore.Abstractions.BaseLinkManager which seems to be the same thing (maybe that is only to conuse us?). Both of above utilize the configured Sitecore.Links.LinkProvider class. And now we have a new one Sitecore.Links.UrlBuilders.ItemUrlBuilder. Feeling a bit lost?
Lets get it sorted – there is no conspiracy really.
What each class is for:
- Sitecore.Abstractions.BaseLinkManager – is supposed to be the default object we communicate to in order to generate item URLs.
- static Sitecore.Links.LinkManager has been kept for backward compatibility and it is utilizing BaseLinkManager inside of it. Still can be used, but why not to stick to the abstraction?
- Sitecore.Links.LinkProvider – configurable provider class for link generation. This class is being utilized inside the default link manager implementation. Should not be used directly.
- Sitecore.Links.UrlBuilders.ItemUrlBuilder – a new class that has been created in result of business logic refactoring. This class is being utilzed by Sitecore.Links.LinkProvider inside and shoud not be used directly, however it gives us the entry point for customizations.