Glass.Mapper 和使用界面创建 Sitecore 项目

本文关键字:创建 Sitecore 项目 界面 Mapper Glass | 更新日期: 2023-09-27 18:32:27

这是来自Twitter的问题:

从接口模型创建项的模式是什么?使用 sitecoreService.Create<T,K>(T newItem, K parent) 其中 T 是一个接口,需要添加一个类来创建新项。有没有办法直接从界面创建它们?

Glass.Mapper 和使用界面创建 Sitecore 项目

这是一个挑战,因为您需要一个具体版本的接口来在保存值之前写入它们。简单的解决方案是使用像NSubstitute这样的模拟框架,使用以下接口:

    [SitecoreType(TemplateId = "{7FC4F278-ADDA-4683-944C-554D0913CB33}", AutoMap = true)]
    public interface StubInterfaceAutoMapped
    {
        Guid Id { get; set; }
        Language Language { get; set; }
        string Path { get; set; }
        int Version { get; set; }
        string Name { get; set; }
        string StringField { get; set; }
    }

我可以创建以下测试:

    [Test]
    public void Create_UsingInterface_CreatesANewItem()
    {
        //Assign
        string parentPath = "/sitecore/content/Tests/SitecoreService/Create";
        string childPath = "/sitecore/content/Tests/SitecoreService/Create/newChild";
        string fieldValue = Guid.NewGuid().ToString();
        var db = Sitecore.Configuration.Factory.GetDatabase("master");
        var context = Context.Create(Utilities.CreateStandardResolver());
        context.Load(new SitecoreAttributeConfigurationLoader("Glass.Mapper.Sc.Integration"));
        var service = new SitecoreService(db);
        using (new SecurityDisabler())
        {
            var parentItem = db.GetItem(parentPath);
            parentItem.DeleteChildren();
        }
        var parent = service.GetItem<StubClass>(parentPath);
        var child = Substitute.For<StubInterfaceAutoMapped>();
        child.Name = "newChild";
        child.StringField = fieldValue;
        //Act
        using (new SecurityDisabler())
        {
            service.Create(parent, child);
        }
        //Assert
        var newItem = db.GetItem(childPath);
        Assert.AreEqual(fieldValue, newItem["StringField"]);
        using (new SecurityDisabler())
        {
            newItem.Delete();
        }
        Assert.AreEqual(child.Name, newItem.Name);
        Assert.AreEqual(child.Id, newItem.ID.Guid);
    }

这是因为 Glass.Mapper 解析要映射的类型的方式:

    /// <summary>
    /// Gets the type configuration.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns>AbstractTypeConfiguration.</returns>
    public AbstractTypeConfiguration GetTypeConfiguration(object obj)
    {
        var type = obj.GetType();
        var config = TypeConfigurations.ContainsKey(type) ? TypeConfigurations[type] : null;
        if (config != null) return config;
        //check base type encase of proxy
        config = TypeConfigurations.ContainsKey(type.BaseType) ? TypeConfigurations[type.BaseType] : null;
        if (config != null) return config;
        //check interfaces encase this is an interface proxy
        string name = type.Name;
        //ME - I added the OrderByDescending in response to issue 53
        // raised on the Glass.Sitecore.Mapper project. Longest name should be compared first
        // to get the most specific interface
        var interfaceType = type.GetInterfaces().OrderByDescending(x=>x.Name.Length).FirstOrDefault(x => name.Contains(x.Name));
        if (interfaceType != null)
            config = TypeConfigurations.ContainsKey(interfaceType) ? TypeConfigurations[interfaceType] : null;
        return config;
    }

请注意,如果找不到直接类型匹配项,它将开始根据与传入类型关联的接口确定类型,并使用基于名称找到的第一个接口。现在我怀疑 NSubstitute 有效,因为它也使用 Castle 动态代理,用其他模拟框架测试它会很有趣。