'How to find out with which Sitecore site an item is associated?

We have a multi-site solution (Site 1 and Site 2), and I need to be able to determine if an item for which we're getting the URL (in the LinkProvider, which is custom) belongs to the current context site (Sitecore.Context.Site), or is part of a different site. Is there a good way to do this?

Basically, we just need to be able to find out to which site the item is associated. We can do the comparison between that value and the current context site.



Solution 1:[1]

I suggest you make an extension method for the Item class that returns a SiteInfo object containing the definition of the site it belongs to.

Unfortunately I don't have my laptop here with all my code, so I just typed it in Visual Studio and made sure it build, but I'm pretty sure it works:

public static class Extensions
{
    public static Sitecore.Web.SiteInfo GetSite(this Sitecore.Data.Items.Item item)
    {
        var siteInfoList = Sitecore.Configuration.Factory.GetSiteInfoList();

        foreach (Sitecore.Web.SiteInfo siteInfo in siteInfoList)
        {
            if (item.Paths.FullPath.StartsWith(siteInfo.RootPath))
            {
                return siteInfo;
            }
        }

        return null;
    }
}

So now you can call the GetSite() method on all Item objects and retrieve the SiteInfo for that item. You can use that to check if it matches your Sitecore.Context.Site, for example by doing:

SiteInfo siteInfo = itemYouNeedToCheck.GetSite();
bool isContextSiteItem = Sitecore.Context.Site.SiteInfo.Equals(siteInfo);

EDIT: I just thought that you could also do it shorter, like this:

public static Sitecore.Web.SiteInfo GetSite(this Sitecore.Data.Items.Item itemYouNeedToCheck)
{
    return Sitecore.Configuration.Factory.GetSiteInfoList()
        .FirstOrDefault(x => itemYouNeedToCheck.Paths.FullPath.StartsWith(x.RootPath));
}

So pick whatever you like best :)

Solution 2:[2]

/// <summary>
/// Get the site info from the <see cref="SiteContextFactory"/> based on the item's path.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>The <see cref="SiteInfo"/>.</returns>
public static SiteInfo GetSiteInfo(this Item item)
{
  return SiteContextFactory.Sites
    .Where(s => !string.IsNullOrWhiteSpace(s.RootPath) && item.Paths.Path.StartsWith(s.RootPath, StringComparison.OrdinalIgnoreCase))
    .OrderByDescending(s => s.RootPath.Length)
    .FirstOrDefault();
}

Solution 3:[3]

I upvoted Ruud van Falier's answer then after a few round of testing I realized that it only works in certain scenarios. Couldn't cancel the vote, so I made some modification to the code here:

    public static SiteInfo GetSite(this Item item)
    {
        var siteInfoList = Sitecore.Configuration.Factory.GetSiteInfoList();

        SiteInfo currentSiteinfo = null;
        var matchLength = 0;
        foreach (var siteInfo in siteInfoList)
        {
            if (item.Paths.FullPath.StartsWith(siteInfo.RootPath, StringComparison.OrdinalIgnoreCase) && siteInfo.RootPath.Length > matchLength)
            {
                matchLength = siteInfo.RootPath.Length;
                currentSiteinfo = siteInfo;
            }
        }

        return currentSiteinfo;
    }

So the issue was that other built-in sites normally have shorter paths like "/sitecore/content" which will match with your content path before it reaches the actual site configuration. So this code is trying to return the best match.

Solution 4:[4]

If you are using Sitecore 9.3+ then you will want to use IItemSiteResolver through dependency injection instead.

IItemSiteResolver _siteResolver;
public MyClass(Sitecore.Sites.IItemSiteResolver siteResolver) {
    _siteResolver = siteResolver;
}

public void DoWork(Item item) {
    Sitecore.Web.SiteInfo site = _siteResolver.ResolveSite(item);
    ...
}

Solution 5:[5]

public static SiteInfo GetSiteInfo(this Item item)
{
    return Sitecore.Links.LinkManager.ResolveTargetSite(item);
}

Solution 6:[6]

This is what I use for our multisite solution.

The FormatWith is just a helper for string.Format.

 public static SiteInfo GetSite(this Item item)
    {
        List<SiteInfo> siteInfoList = Factory.GetSiteInfoList();
        SiteInfo site = null;
        foreach (SiteInfo siteInfo in siteInfoList)
        {
            var siteFullPath = "{0}{1}".FormatWith(siteInfo.RootPath, siteInfo.StartItem);
            if (string.IsNullOrWhiteSpace(siteFullPath))
            {
                continue;
            }
            if (item.Paths.FullPath.StartsWith(siteFullPath, StringComparison.InvariantCultureIgnoreCase))
            {
                site = siteInfo;
                break;
            }
        }
        return site;
    }

Solution 7:[7]

And to avoid dependencies, for unit test purposes, I've created a method to extract this information from web.config directly:

    public static SiteInfoVM GetSiteInfoForPath(string itemPath)
    {
        var siteInfos = GetSiteInfoFromXml();

        return siteInfos
            .Where(i => i.RootPath != "/sitecore/content" && itemPath.StartsWith(i.RootPath))
            //.Dump("All Matches")
            .OrderByDescending(i => i.RootPath.Length).FirstOrDefault();
    }

    static List<SiteInfoVM> GetSiteInfoFromXml()
    {

        XmlNode sitesNode = Sitecore.Configuration.ConfigReader.GetConfigNode("sites");//.Dump();
        var result = sitesNode.Cast<XmlNode>()
        .Where(xn => xn.Attributes != null && xn.Attributes["rootPath"] != null
        //&& (xn.Attributes["targetHostName"]!=null ||  xn.Attributes["name"].Value)
        )
        .Select(xn => new {
            Name = xn.Attributes["name"].Value,
            RootPath = xn.Attributes["rootPath"].Value,
            StartItem = xn.Attributes["startItem"].Value,
            Language = xn.Attributes["language"] != null ? xn.Attributes["language"].Value : null,
            TargetHostName = (xn.Attributes["targetHostName"] != null) ? xn.Attributes["targetHostName"].Value : null,
            SiteXml = xn.OuterXml
        })
        .Select(x => new SiteInfoVM(x.Name, x.RootPath, x.StartItem, x.Language, x.TargetHostName, x.SiteXml))
        .ToList();
        return result;
    }


    public class SiteInfoVM
    {

        public SiteInfoVM(string name, string rootPath, string startItem, string lang, string tgtHostName, string siteXml)
        {
            Name = name;
            TargetHostName = tgtHostName;
            RootPath = rootPath;
            StartItem = startItem;
            Language = lang;
            SiteXml = siteXml;


        }
        public string Name { get; set; }
        public string RootPath { get; set; }
        public string StartItem { get; set; }
        public string Language { get; set; }
        public string TargetHostName { get;set; }
        public string SiteXml { get; set; }
    }

Solution 8:[8]

public static class SiteResolver
{
    public static SiteContext ResolveSitebyItem(Item contentItem)
    {
        var site = Factory.GetSiteInfoList().FirstOrDefault(
            x => contentItem.Paths.Path.Contains(x.RootPath) &&
            x.RootPath != "/sitecore/content" &&
            x.Domain == "extranet"
            );

        if (site is SiteInfo siteInfo)
        {
            return new SiteContext(siteInfo);
        }

        return Sitecore.Context.Site;
    }
}

Solution 9:[9]

I believe this is better solution http://firebreaksice.com/sitecore-context-site-resolution/

public static Sitecore.Web.SiteInfo GetSite(Sitecore.Data.Items.Item item)
{
    var siteInfoList = Sitecore.Configuration.Factory.GetSiteInfoList();

    foreach (Sitecore.Web.SiteInfo siteInfo in siteInfoList)
    {
        var homePage = Sitecore.Context.Database.GetItem(siteInfo.RootPath + siteInfo.StartItem);

        if (homePage != null && homePage.Axes.IsAncestorOf(item))
        {
            return siteInfo;
        }
    }
    return null;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 BraveNewMath
Solution 2 WizxX20
Solution 3 zhanke
Solution 4
Solution 5 staccata
Solution 6 Roland
Solution 7 BraveNewMath
Solution 8 Sathyamoorthy Sri
Solution 9 Donald Duck