Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sitecore LinkManager GetItemUrl. Why its so tricky?

I have task to get content's url when smth is changed on website. It like CRUD operation logging (In my case i am logging that urls to other system to further processing). It should work on version 6 and higher.

When i started it seems pretty simple subscribe to event then take item and generate url for it. I subscribed to two events publish:itemProcessing (because only here item is not yet removed from web database), publish:itemProcessed (for add and update).

This events give me object of time Item, so it seems to get url pretty simple like that

var options = LinkManager.GetDefaultUrlOptions();
options.AlwaysIncludeServerUrl = true;
options.SiteResolving = true;
var url = LinkManager.GetItemUrl(item, options);

And here my problem starts. First i need to have right url and the same way as it is generated on website but here url returns me smth like "http://domain/sitecore/content/Home.aspx".

So I added new methods to find right site from site definitions

private List<KeyValuePair<string, SiteContext>> GetSites()
{
            return SiteManager.GetSites()
                .Where(
                    s =>
                        !string.IsNullOrEmpty(s.Properties["rootPath"]) &&
                        !string.IsNullOrEmpty(s.Properties["startItem"]))
                .Select(
                    d => new KeyValuePair<string, SiteContext>($"{d.Properties["rootPath"]}{d.Properties["startItem"]}",
                        new SiteContext(new SiteInfo(d.Properties))))
                .ToList();
}

public virtual SiteContext GetSiteContext(Item item)
{

            var site = _sites.LastOrDefault(s => item.Paths.FullPath.ToLower().StartsWith(s.Key.ToLower()));
            return site.Value;
}

options.Site = GetSiteContext(Item item);

Again issue is not solved because sitecore returns "http://127.0.0.1/en.aspx"

Then i continue reading and understood that site definition should have targetHostName (it actually make sense since one site can have multiple domains) but when i add targetHostName now it returns me other link "://targetHostName/en.aspx" so http|https is missing. Second problem is that it returns me EN.aspx which means that this page can be accessible throw http://targetHostName/en.aspx and http://targetHostName

Now i have following site definitions

 <sites>
      <site name="shell" virtualFolder="/sitecore/shell" physicalFolder="/sitecore/shell" rootPath="/sitecore/content" startItem="/home" language="en" database="core" domain="sitecore" loginPage="/sitecore/login" content="master" contentStartItem="/Home" enableWorkflow="true" enableAnalytics="false" analyticsDefinitions="content" xmlControlPage="/sitecore/shell/default.aspx" browserTitle="Sitecore" htmlCacheSize="2MB" registryCacheSize="3MB" viewStateCacheSize="200KB" xslCacheSize="5MB" />
      <site name="login" virtualFolder="/sitecore/login" physicalFolder="/sitecore/login" enableAnalytics="false" database="core" domain="sitecore" disableXmlControls="true" />
      <site name="admin" virtualFolder="/sitecore/admin" physicalFolder="/sitecore/admin" enableAnalytics="false" enableWorkflow="true" domain="sitecore" loginPage="/sitecore/admin/login.aspx" />
      <site name="service" virtualFolder="/sitecore/service" physicalFolder="/sitecore/service" />
      <site name="modules_shell" virtualFolder="/sitecore modules/shell" physicalFolder="/sitecore modules/shell" rootPath="/sitecore/content" startItem="/home" language="en" database="core" domain="sitecore" content="master" enableAnalytics="false" enableWorkflow="true" />
      <site name="modules_website" virtualFolder="/sitecore modules/web" physicalFolder="/sitecore modules/web" rootPath="/sitecore/content" startItem="/home" language="en" database="web" domain="extranet" allowDebug="true" cacheHtml="true" />
      <site name="website" hostName="sitecore6.target|sitecore6.local" targetHostName="sitecore6.target" schema="http" virtualFolder="/" physicalFolder="/" rootPath="/sitecore/content" startItem="/home" database="web" domain="extranet" allowDebug="true" cacheHtml="true" htmlCacheSize="10MB" registryCacheSize="0" viewStateCacheSize="0" xslCacheSize="5MB" filteredItemsCacheSize="2MB" enablePreview="true" enableWebEdit="true" enableDebugger="true" disableClientData="false" />
      <site name="scheduler" enableAnalytics="false" domain="sitecore" />
      <site name="system" enableAnalytics="false" domain="sitecore" />
      <site name="publisher" domain="sitecore" enableAnalytics="false" enableWorkflow="true" />
    </sites>

And link manager settings

 <linkManager defaultProvider="sitecore">
      <providers>
        <clear />
        <add name="sitecore" type="Sitecore.Links.LinkProvider, Sitecore.Kernel" addAspxExtension="true" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="asNeeded" languageLocation="filePath" lowercaseUrls="false" shortenUrls="true" useDisplayName="false" />
      </providers>
    </linkManager>
like image 438
Vova Bilyachat Avatar asked Dec 03 '22 15:12

Vova Bilyachat


1 Answers

The problem is occurring because of where you are generating the link. When you have the AlwaysIncludeServerUrl option set to true, Sitecore will use the current Sitecore.Context.Site information to work out the server Url.

To set the http or https section, you need to add an attribute called scheme to your site definition - I think you just have a typo as you had one called schema:

<sites>
    <site name="website" hostName="sitecore6.target|sitecore6.local" targetHostName="sitecore6.target" scheme="http" virtualFolder="/" physicalFolder="/" rootPath="/sitecore/content" startItem="/home" database="web" domain="extranet" allowDebug="true" cacheHtml="true" htmlCacheSize="10MB" registryCacheSize="0" viewStateCacheSize="0" xslCacheSize="5MB" filteredItemsCacheSize="2MB" enablePreview="true" enableWebEdit="true" enableDebugger="true" disableClientData="false" />
</sites>

During a publish event, that Context.Site will be the shell website. So it will not pickup the targetHostName for your website definition.

To force that, you need to use a SiteContextSwitcher

var website = Sitecore.Configuration.Factory.GetSite("website");
using (new SiteContextSwitcher(website))
{
    var options = LinkManager.GetDefaultUrlOptions();
    options.AlwaysIncludeServerUrl = true;
    options.SiteResolving = true;
    var url = LinkManager.GetItemUrl(item, options);
}

Then the Url will be generated using the website's targetHostName and should generate how you are expecting.

Just one last note - best practice would be to patch the new Site definition via an include file rather than edit the main Sitecore config. Check out your include folder, there should be a SiteDefinition.config.example file in there. It shows you how to do it.

like image 189
Richard Seal Avatar answered Dec 15 '22 02:12

Richard Seal