0

After upgrading our solution from Sitecore 9.0.2 -> 10.1.2 we started encountering an issue where the .Parent property on the interface below is intermittently returned as null. It appears that when the this issue is occurring for one item with a given template, it is also occurring to all/many other items with the same template. Other types inheriting from IGlassBase do not appear to have the same issue.

The issue appears to vary by template on every app recycle - on one app recycle, the .parent property may work for our video template, but not documents, and vice versa after an IISRESET. This makes me think caching may be somehow related, but none of the changes I've tried have made any difference.

I also tried overriding Glass.Mapper.Sc.DataMappers.SitecoreParentMapper and found that SitecoreParentMapper was not being executed when the property was returned as null.

When inspecting the type of our Glass Models when the .Parent property was correct, I see a type named like this - Castle.Proxies.IExternalDocumentProxy . When the property is null, calling .GetType() returns Castle.Proxies.ExternalDocumentProxy. When the property is null I cannot inspect the model in the debugger at all, but I am unsure what the significance/meaning of that would be.

The issue does not occur on a fresh Sitecore 10.1.2 instance and is somehow related to our solution build but I'm struggling to figure out how to further debug this issue.

public interface IGlassBase {

    [SitecoreId]
    ID Id { get; }

    .......

    [SitecoreParent(InferType = true)]
    IGlassBase Parent { get; }

    [SitecoreChildren(InferType = true)]
    IEnumerable<IGlassBase> Children { get; set; }

}

public partial interface IExternalMedia : IGlassBase, zzzzzzz.yyyyy.Model.Sitecore.Misc.IBaseTemplate {
    /// <summary>
    /// The Asset Name field.
    /// <para>Field Type: Single-Line Text</para>
    /// <para>Field ID: a94ec4a7-6f5f-4ad6-914d-c71ec9846727</para>
    /// </summary>
    [SitecoreField(ExternalMediaConstants.AssetNameFieldIdString)]
    string AssetName { get; set; }

}

public static IEnumerable<IExternalMedia> GetMedia(this ISitecoreService service, IProduct product, string mediaType) {
        if (product.ProductAssets == null || product.InnerItem?.Database == null || string.IsNullOrEmpty(mediaType)) {
            return new List<IExternalMedia>();
        }

        string mediaPath = $"{product.ProductAssets.ItemFullPath}/{mediaType}";
        Item mediaFolder = product.InnerItem.Database.GetItem(mediaPath);
        IAssetFolder mediaItem = service.GetItem<IAssetFolder>(new GetItemByItemOptions { Item = mediaFolder });
        IEnumerable<IExternalMedia> mediaList = mediaItem?.Children?.OfType<IExternalMedia>() ?? new List<IExternalMedia>();
        // at this point, it is a coin toss whether the items in mediaList have .Parent property values or are null. 

        return mediaList;
    }
2
  • Have you tried virtual keyword? public virtual IGlassBase Parent { get; }. Refer sitecore.stackexchange.com/questions/18193/… Jan 12 at 4:56
  • I have virtual keywords on all my glass class properties (which I'm not using here) but you can't use virtual keyword with interfaces
    – byed
    Jan 12 at 5:04

1 Answer 1

1

The problem was that even though my model was requesting items of type IGlassBase, I also had definitions for a concrete class named GlassBase in the same DLL. We were providing GlassMapper a reference to that DLL in GlassMapperScCustom.GlassLoaders. That GlassLoaders method would load all types in that DLL and create the scaffolding to create those types internally.

When I was encountering the issue for a given type, I was receiving a type from GlassMapper that inherited from GlassBase and not just IGlassBase. GlassBase did not have a setter on the parent property. Adding a setter fixed the issue.

It seems like GlassMapper does not require a setter on interface type parent properties, but it does on class types in SC 10+.

public static IConfigurationLoader[] GlassLoaders() {
     AttributeConfigurationLoader loader = new AttributeConfigurationLoader("MyProject.Common");
     return new IConfigurationLoader[] { loader };
} 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.