Question

In Sitecore 7, it is now possible to create model definition items under /sitecore/layout/Models and link them to my Layouts and Renderings (as opposed to hard-coding the type + assembly on each one). This makes it much easier to manage, especially if I ever need to update my namespaces or see which layouts are using a particular model.

That said, I have hit an issue whereby Glass.Mapper appears to parse the 'Model' field as though it is a text field, when it is in fact an Internal Link field. Here is the error I am getting:

Could not load type '/sitecore/layout/Models/HomeViewModel' from assembly 'Glass.Mapper.Sc, Version=3.0.2.8, Culture=neutral, PublicKeyToken=null'.

Does anyone now if Glass supports linking to Models in Sitecore 7, or am I correct to assume that it's just not resolving the Internal Link field to the Model?

Was it helpful?

Solution

UPDATE: This works properly now in the latest version, none of what I said below is needed anymore, keeping for posterity's sake.

I ran into this problem myself and unfortunately it does not appear as if this is supported. I looked on the Trello for Glass and it looks like Sitecore 7 testing/support is an upcoming task although it mostly works in its current form aside from one or two issues.

That being said since it's open source it's not too much of a hassle to get it working yourself. Below is the full code for the Glass.Mapper.Sc.Pipelines.Response.GetModel class which I've modified to resolve two issues I was having

  1. The issue you've mentioned
  2. Extending the class to allow for automatically using the DataSource instead of the context item to generate the model. I've included a comment in the code to let you know how to disable this portion of the file, because it relies on another change elsewhere in the library (but I can provide that as well if you'd like).

Please note that I have not modified all methods in this class, just the ones that have broken for me so far. The modifications themselves are fairly straightforward (just make it look for the linked item instead of a text field). I hope this helps.

public class GetModel : GetModelProcessor
{
    public GetModel()
    {
        ContextName = "Default";

    }
    public string ContextName { get; set; }

    public override void Process(GetModelArgs args)
    {
        if (args.Result == null)
        {
            Rendering rendering = args.Rendering;
            if (rendering.RenderingType == "Layout")
            {
                args.Result = GetFromItem(rendering, args);
                if (args.Result == null)
                {
                    args.Result = GetFromLayout(rendering, args);
                }
            }
            if (args.Result == null)
            {
                args.Result = GetFromPropertyValue(rendering, args);
            }
            if (args.Result == null)
            {
                args.Result = GetFromField(rendering, args);
            }
        }
    }
    protected virtual object GetFromField(Rendering rendering, GetModelArgs args)
    {
        Item obj = ObjectExtensions.ValueOrDefault<RenderingItem, Item>(rendering.RenderingItem, (Func<RenderingItem, Item>)(i => i.InnerItem));
        if (obj == null)
            return (object)null;

        Item model = MvcSettings.GetRegisteredObject<ItemLocator>().GetItem(obj["Model"]);

        if (model == null)
            return (object)null;
        else
            return GetObject(model["Model Type"], rendering);
    }
    protected virtual object GetFromPropertyValue(Rendering rendering, GetModelArgs args)
    {
        string model = rendering.Properties["Model"];
        if (StringExtensions.IsWhiteSpaceOrNull(model))
            return (object)null;
        else
            return GetObject(model, rendering);
    }

    protected virtual object GetFromLayout(Rendering rendering, GetModelArgs args)
    {
        string pathOrId = rendering.Properties["LayoutId"];
        if (StringExtensions.IsWhiteSpaceOrNull(pathOrId))
            return (object)null;
        string modelItemPath = ObjectExtensions.ValueOrDefault<Item, string>(MvcSettings.GetRegisteredObject<ItemLocator>().GetItem(pathOrId), (Func<Item, string>)(i => i["Model"]));
        string model = ObjectExtensions.ValueOrDefault<Item, string>(MvcSettings.GetRegisteredObject<ItemLocator>().GetItem(modelItemPath), (Func<Item, string>)(i => i["Model Type"]));
        if (StringExtensions.IsWhiteSpaceOrNull(model))
            return (object)null;
        else
            return GetObject(model, rendering);
    }

    protected virtual object GetFromItem(Rendering rendering, GetModelArgs args)
    {
        string model = ObjectExtensions.ValueOrDefault<Item, string>(rendering.Item, (Func<Item, string>)(i => i["MvcLayoutModel"]));
        if (StringExtensions.IsWhiteSpaceOrNull(model))
            return (object)null;
        else
            return GetObject(model, rendering);
    }


    public object GetObject(string model, Rendering rendering)
    {

        if (model.IsNullOrEmpty())
            return null;

        var type = Type.GetType(model, true);

        if (type == null)
            return null;

        var context = Context.Contexts[ContextName];
        if (context == null) throw new MapperException("Failed to find context {0}".Formatted(ContextName));

        if (context.TypeConfigurations.ContainsKey(type))
        {
            ISitecoreContext scContext = new SitecoreContext(context);

            //comment this if block out if you just need to solve the model link problem
            if (rendering != null)
            {
                if (rendering.Item != null)
                {                        
                    var dataSourceResult = scContext.GetCurrentItem(type, itemOverride: rendering.Item);
                    return dataSourceResult;
                }
            }

            var result = scContext.GetCurrentItem(type);
            return result;
        }
        return null;
    }


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