Question

Using Glass Mapper V3, is it possible to check whether a Sitecore item supports a specific Glass Mapper class/interface?

Given these classes

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

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

I would like to do something like this

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

Unfortunately, if I do that, I do get an item of the type IRateableItem returned, regardless of whether the current item is composed of that template or not.

Was it helpful?

Solution

Dan

Another solution would be to create a custom task that runs in the ObjectConstruction pipeline.

Something like this:

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

You would then change you IRateableItem inteface to have the template ID it needs to match and inherit from ITemplateCheck:

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

Finally you will need to register the new task with the Castle IOC container in GlassMapperScCustom:

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

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

I haven't had a chance to test this so let me know if there are any problems.

OTHER TIPS

I used this code to determine if an Item could be loaded as a Glass model of a certain type. I've used your IRateableItem type as an example:

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

EDIT:
Add this extension method so that you can determine whether a Template inherits from a certain base template.

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

So now you can do this:

if (item.Template.InheritsFrom(GetSitecoreTypeTemplateId<IRateableItem>()))
{
  // item is of type IRateableItem
}

I haven't found a solution to the null-check as well. But what you can do is this:

First add the TemplateId to the SitecoreType attribute for both your models:

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

Then in your code use the GetCurrentItem<>() method with the InferType=true parameter:

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

By adding the TemplateID and using the InferType:true parameter, Glass will try to map the item to a better object then IGlassBase, based on the TemplateID.

If there is a nicer solution to solve this, I'm interested as well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top