Проверка типов Glass Mapper V3 во время выполнения

Можно ли с помощью Glass Mapper V3 проверить, поддерживает ли элемент Sitecore определенный класс/интерфейс Glass Mapper?

Учитывая эти классы

[SitecoreType]
public partial interface IPage : IGlassBase
{
  // ... some properties here ...
}

[SitecoreType]
public partial interface IRateableItem : IGlassBase
{
  // ... some properties here ...
}

Я хотел бы сделать что-то подобное

var context = SitecoreContext();
var item = context.GetCurrentItem<IRateableItem>();
if (item != null)
  // it's an item that is composed of the Rateable Item template

К сожалению, если я это сделаю, я получу возвращенный элемент типа IRateableItem, независимо от того, состоит ли текущий элемент из этого шаблона или нет.


person Dan Sinclair    schedule 22.10.2013    source источник
comment
Я напишу пример и опубликую его завтра.   -  person Michael Edwards    schedule 23.10.2013


Ответы (3)


Дэн

Другим решением было бы создание пользовательской задачи, которая выполняется в конвейере ObjectConstruction.

Что-то вроде этого:

public class LimitByTemplateTask : IObjectConstructionTask
{
    private static readonly Type _templateCheck = typeof (ITemplateCheck);

    public void Execute(ObjectConstructionArgs args)
    {
        if (args.Result != null)
            return;

        if ( _templateCheck.IsAssignableFrom(args.AbstractTypeCreationContext.RequestedType))
        {
            var scContext = args.AbstractTypeCreationContext as SitecoreTypeCreationContext;
            var config = args.Configuration as SitecoreTypeConfiguration;

            var template = scContext.SitecoreService.Database.GetTemplate(scContext.Item.TemplateID);

            //check to see if any base template matched the template for the requested type
            if (template.BaseTemplates.All(x => x.ID != config.TemplateId) && scContext.Item.TemplateID != config.TemplateId)
            {
                args.AbortPipeline();
            }
        }
    }
}


public interface ITemplateCheck{}

Затем вы должны изменить интерфейс IRateableItem, чтобы он имел идентификатор шаблона, который должен совпадать и наследоваться от ITemplateCheck:

[SitecoreType(TemplateId = "CF9B175D-872E-439A-B358-37A01155EEB1")]
public interface IRateableItem: ITemplateCheck, IGlassBase{}

Наконец, вам нужно будет зарегистрировать новую задачу в контейнере Castle IOC в GlassMapperScCustom:

    public static void CastleConfig(IWindsorContainer container){
        var config = new Config();

        container.Register(
            Component.For<IObjectConstructionTask>().ImplementedBy<LimitByTemplateTask>(),
            );
        container.Install(new SitecoreInstaller(config));
    }

У меня не было возможности проверить это, поэтому дайте мне знать, если есть какие-либо проблемы.

person Michael Edwards    schedule 23.10.2013
comment
Спасибо, Майк, за этот быстрый ответ! К сожалению, изменений в поведении не заметил. Я не получил никаких исключений или других проблем, но я все еще могу получить элемент, даже если он не состоит из шаблона оцениваемого элемента (т. е. new SitecoreContext().GetCurrentItem‹IRateableItem›() возвращает значение). Я что-то упускаю? - person Dan Sinclair; 24.10.2013
comment
Дэн, я делаю IsAssignableFrom неправильно. Я проверил выше, и он работает, как ожидалось - person Michael Edwards; 24.10.2013
comment
Хороший улов! Ага; который позаботился об этом для меня. Я рассматриваю возможность обновления проверки BaseTemplate, чтобы она была рекурсивной, аналогичной коду @Ruud, но меня беспокоит производительность во время выполнения. Пока я оставлю все как есть, чтобы посмотреть, нужна ли нам большая глубина шаблона. Спасибо! - person Dan Sinclair; 24.10.2013
comment
Это решение действительно помогло мне. По какой-то причине у меня были случаи, когда Context.Item содержал элемент контента, поэтому я просто проверял это с помощью ItemIDs.ContentRoot и возвращался. - person Coding101; 26.11.2013

Я использовал этот код, чтобы определить, может ли предмет быть загружен как модель стекла определенного типа. Я использовал ваш тип IRateableItem в качестве примера:

public void Main()
{
    var item = Sitecore.Context.Item;

    if (item.TemplateID.Equals(GetSitecoreTypeTemplateId<IRateableItem>()))
    {
        // item is of the IRateableItem type
    }
}

private ID GetSitecoreTypeTemplateId<T>() where T : class
{
    // Get the GlassMapper context
    var context = GetGlassContext();

    // Retrieve the SitecoreTypeConfiguration for type T
    var sitecoreClass = context[typeof(T)] as SitecoreTypeConfiguration;

    return sitecoreClass.TemplateId;
}

private SitecoreService GetSitecoreService()
{
    return new SitecoreService(global::Sitecore.Context.Database);
}

private Glass.Mapper.Context GetGlassContext()
{
    return GetSitecoreService().GlassContext;
}

РЕДАКТИРОВАТЬ:
Добавьте этот метод расширения, чтобы можно было определить, наследуется ли шаблон от определенного базового шаблона.

public static bool InheritsFrom(this TemplateItem templateItem, ID templateId)
{
    if (templateItem.ID == templateId)
    {
        return true;
    }

    foreach (var template in templateItem.BaseTemplates)
    {
        if (template.ID == templateId)
        {
            return true;
        }

        if (template.InheritsFrom(templateId))
        {
            return true;
        }
    }

    return false;
}

Итак, теперь вы можете сделать это:

if (item.Template.InheritsFrom(GetSitecoreTypeTemplateId<IRateableItem>()))
{
  // item is of type IRateableItem
}
person Ruud van Falier    schedule 23.10.2013
comment
Спасибо, Рууд, за быстрый ответ. К сожалению, мои элементы состоят из IRateableItem, который не является их основным шаблоном. Так что эта проверка всегда будет возвращать false в моем случае. Однако это будет работать и для других типов, если проверяемый шаблон является основным шаблоном элемента. - person Dan Sinclair; 24.10.2013
comment
Обновлен мой ответ методом расширения, который проверяет, наследуется ли шаблон от определенного базового шаблона. - person Ruud van Falier; 24.10.2013
comment
Ага, так бы и было. В итоге я выбрал решение от @MichaelEdwards, потому что 1) оно не требует проверки перед попыткой получить предмет и 2) не требует, чтобы у меня был Sitecore.Data.Items.Item. Теоретически это упростит код и сделает его более тестируемым. - person Dan Sinclair; 24.10.2013

Я также не нашел решения для нулевой проверки. Но что вы можете сделать, так это:

Сначала добавьте TemplateId в атрибут SitecoreType для обеих моделей:

[SitecoreType(TemplateId = "{your-template-id}")]

Затем в своем коде используйте метод GetCurrentItem‹>() с параметром InferType=true:

 var context = SitecoreContext();
 var item = context.GetCurrentItem<IGlassBase>(InferType: true);
 if (item is IRateableItem)
  {
    var rateableItem = item as IRateableItem;
    // do more...
  }

Добавляя TemplateID и используя параметр InferType:true, Glass попытается сопоставить элемент с более подходящим объектом, чем IGlassBase, на основе TemplateID.

Если есть более приятное решение для решения этой проблемы, мне тоже интересно.

person Martijn van der Put    schedule 22.10.2013
comment
Спасибо, Мартин. Это сработает, но только в том случае, если основным шаблоном элемента является Оцениваемый предмет, а не если он состоит из Оцениваемого предмета. - person Dan Sinclair; 24.10.2013