Glass.Mapper并使用Interfaces创建Sitecore项

时间:2013-09-24 06:32:08

标签: c# sitecore glass-mapper

这是question from Twitter

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

1 个答案:

答案 0 :(得分:4)

这是一个挑战,因为您需要具体版本的界面才能在保存之前写入值。简单的解决方案是使用像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 Dynamic Proxies,用其他模拟框架测试它会很有趣。