【问题标题】:How to find out with which Sitecore site an item is associated?如何找出项目与哪个 Sitecore 站点相关联?
【发布时间】:2013-01-07 17:21:21
【问题描述】:

我们有一个多站点解决方案(站点 1 和站点 2),我需要能够确定我们获取 URL(在 LinkProvider 中,这是自定义的)的项目是否属于当前上下文站点 (Sitecore.Context.Site),或者是其他站点的一部分。有什么好办法吗?

基本上,我们只需要能够找出该项目与哪个站点相关联。我们可以将该值与当前上下文站点进行比较。

【问题讨论】:

  • 一个项目可以“属于”多个站点。我认为不会有通用的解决方案,这取决于您的配置。
  • 是的,定义“属于”。如果您的意思是“在当前上下文站点根路径之下”,那么 Ruud 的答案就是您所需要的。

标签: sitecore


【解决方案1】:

我建议您为 Item 类创建一个扩展方法,该方法返回一个 SiteInfo 对象,其中包含它所属站点的定义。

不幸的是,我的笔记本电脑上没有我的所有代码,所以我只是在 Visual Studio 中输入它并确保它构建,但我很确定它可以工作:

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;
    }
}

所以现在您可以对所有Item 对象调用GetSite() 方法并检索该项目的SiteInfo。 您可以使用它来检查它是否与您的Sitecore.Context.Site 匹配,例如通过执行以下操作:

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

编辑:我只是认为你也可以缩短它,像这样:

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));
}

所以选择你最喜欢的:)

【讨论】:

  • 这仅适用于每个项目只有一个可能的上下文站点,如果您有多个域指向同一个主项目(例如,支持国家/语言特定域),则情况并非如此。这个问题实际上存在不同的问题:1)这个项目是当前站点内容树的一部分,2)如果不是,它属于哪个站点。
  • web.config 中站点定义的顺序很重要,因为它决定了如何解析“属于”多个站点的项目。
  • 如果您有多个站点,其中一些站点的路径较短且与其他站点发生冲突,您可以在 RootPath.Length 上进行 OrderByDescending,以便首先匹配最具体的站点。
  • 您可能还想检查站点的域,以确保它不是 sitecore shell。类似if (item.Paths.FullPath.StartsWith(siteInfo.RootPath) && siteInfo.Domain != "sitecore")
【解决方案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();
}

【讨论】:

  • 我很喜欢@BraveNewMath
【解决方案3】:

我赞成 Ruud van Falier 的回答,然后经过几轮测试,我意识到它只在某些情况下有效。无法取消投票,所以我在这里对代码进行了一些修改:

    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;
    }

所以问题在于其他内置网站通常具有较短的路径,例如“/sitecore/content”,它会在到达实际站点配置之前与您的内容路径匹配。所以这段代码试图返回最佳匹配。

【讨论】:

  • ` public static SiteInfo GetSite(this Item item) { return Factory.GetSiteInfoList().OrderByDescending(i => i.RootPath) .FirstOrDefault(x => item.Paths.FullPath.StartsWith(x .RootPath)); }`
  • @jrap: OrderByDescending(i => i.RootPath) 应该是 OrderByDescending(i => i.RootPath.Length)
【解决方案4】:

如果您使用的是 Sitecore 9.3+,那么您将希望通过依赖注入来使用 IItemSiteResolver

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

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

【讨论】:

  • 你能提供一个 siteResolver 的直接实例化的例子吗?
【解决方案5】:
public static SiteInfo GetSiteInfo(this Item item)
{
    return Sitecore.Links.LinkManager.ResolveTargetSite(item);
}

【讨论】:

  • 这并不总是有效。我已经尝试过了,如果您有一个结构,例如,您的内容位于任何站点的起始项层次结构之外,但仍希望它解析为可能基于“SiteRoot”后代的站点" 项,它将无法正确解析站点并返回默认的“网站”
  • 这在 Sitecore 9.3 中已过时
【解决方案6】:

这是我用于我们的多站点解决方案的。

FormatWith 只是 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;
    }

【讨论】:

    【解决方案7】:

    为了避免依赖,出于单元测试的目的,我创建了一个方法来直接从 web.config 中提取这些信息:

        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; }
        }
    

    【讨论】:

      【解决方案8】:

      我相信这是更好的解决方案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;
      }
      

      【讨论】:

      • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation 将通过展示为什么这是解决问题的好方法,并使其对有其他类似问题的未来读者更有用,从而大大提高其长期价值。请edit您的回答添加一些解释,包括您所做的假设。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多