如何找出项目与哪个Sitecore站点关联?

如何找出项目与哪个Sitecore站点关联?,sitecore,Sitecore,我们有一个多站点解决方案(站点1和站点2),我需要能够确定获取URL的项目(在LinkProvider中,这是自定义的)是否属于当前上下文站点(Sitecore.context.site),或者是其他站点的一部分。有什么好办法吗 基本上,我们只需要能够找到该项目与哪个站点关联。我们可以将该值与当前上下文站点进行比较 我建议您为Item类创建一个扩展方法,该方法返回一个SiteInfo对象,该对象包含它所属站点的定义 不幸的是,我的笔记本电脑中没有我所有的代码,所以我只是在Visual Studi

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


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

我建议您为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));
}

所以选择你最喜欢的:)

这就是我在多站点解决方案中使用的

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;
    }
publicstaticsiteinfogetsite(此项)
{
List siteInfoList=Factory.GetSiteInfoList();
siteinfosite=null;
foreach(站点信息列表中的站点信息站点信息)
{
var siteFullPath=“{0}{1}”.FormatWith(siteInfo.RootPath,siteInfo.StartItem);
if(string.IsNullOrWhiteSpace(siteFullPath))
{
继续;
}
if(item.path.FullPath.StartsWith(siteFullPath、StringComparison.invariantCultureInogoreCase))
{
site=siteInfo;
打破
}
}
返回站点;
}

我对路德·范法利尔的答案投了赞成票,经过几轮测试后,我意识到它只在某些情况下有效。无法取消投票,因此我对此处的代码进行了一些修改:

    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”,它将在到达实际站点配置之前与您的内容路径匹配。因此,此代码试图返回最佳匹配。

//
/// <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();
}
///根据项目的路径从获取站点信息。 /// ///这个项目。 ///这个。 公共静态SiteInfo GetSiteInfo(此项) { 返回SiteContextFactory.Sites .Where(s=>!string.IsNullOrWhiteSpace(s.RootPath)和&item.Path.Path.StartsWith(s.RootPath,StringComparison.OrdinalIgnoreCase)) .OrderByDescending(s=>s.RootPath.Length) .FirstOrDefault(); }
为了避免依赖关系,出于单元测试的目的,我创建了一种方法,直接从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; }
    }
publicstaticsiteinfovmgetsiteinfoforpath(stringitempath)
{
var siteInfos=getsiteinforomxml();
返回站点信息
.Where(i=>i.RootPath!=“/sitecore/content”&&itemPath.StartsWith(i.RootPath))
//.Dump(“所有匹配项”)
.OrderByDescending(i=>i.RootPath.Length).FirstOrDefault();
}
静态列表GetSiteInfoFromXml()
{
XmlNode sitesNode=Sitecore.Configuration.ConfigReader.GetConfigNode(“站点”);/.Dump();
var result=sitesNode.Cast()
.Where(xn=>xn.Attributes!=null&&xn.Attributes[“rootPath”]!=null
//&&(xn.Attributes[“targetHostName”]!=null | | xn.Attributes[“name”]值)
)
.选择(xn=>new{
Name=xn.属性[“Name”].值,
RootPath=xn.Attributes[“RootPath”].Value,
StartItem=xn.属性[“StartItem”].值,
Language=xn.Attributes[“Language”!=null?xn.Attributes[“Language”]。值:null,
TargetHostName=(xn.Attributes[“TargetHostName”]!=null)?xn.Attributes[“TargetHostName”]。值:null,
SiteXml=xn.OuterXml
})
.Select(x=>newsiteinfovm(x.Name,x.RootPath,x.StartItem,x.Language,x.TargetHostName,x.SiteXml))
.ToList();
返回结果;
}
公共类SiteInfoVM
{
publicsiteinfovm(字符串名称、字符串根路径、字符串startItem、字符串lang、字符串tgtHostName、字符串siteXml)
{
名称=名称;
TargetHostName=tgtHostName;
RootPath=RootPath;
StartItem=StartItem;
语言=语言;
SiteXml=SiteXml;
}
公共字符串名称{get;set;}
公共字符串根路径{get;set;}
公共字符串StartItem{get;set;}
公共字符串语言{get;set;}
公共字符串TargetHostName{get;set;}
公共字符串SiteXml{get;set;}
}

我认为这是更好的解决方案


如果您使用的是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);
    ...
}

一个项目可以“属于”多个站点。我不认为会有一个通用的解决方案,它将取决于您的配置。是的,定义“属于”。如果您的意思是“位于当前上下文站点根路径之下”,那么Ruud的回答就是您所需要的。这只适用于每个项目只有一个可能的上下文站点的情况,如果您有多个域指向同一个主项目(例如,支持特定国家/语言的域),则情况并非如此。这个问题实际上有不同的问题:1)此项目是否属于当前网站内容树的一部分,2)如果不是,它属于哪个网站。web.config中网站定义的顺序很重要,因为它指示如何解决“属于”多个网站的项目。如果有多个网站,其中一些路径较短,与其他路径冲突,您可以通过在RootPath.Length上降序来排序,以便
public static SiteInfo GetSiteInfo(this Item item)
{
    return Sitecore.Links.LinkManager.ResolveTargetSite(item);
}
IItemSiteResolver _siteResolver;
public MyClass(Sitecore.Sites.IItemSiteResolver siteResolver) {
    _siteResolver = siteResolver;
}

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