MvcSiteMapProvider:如何从 MVC 4 中启用 MEF 的模块加载额外的 web.sitemap 文件

MvcSiteMapProvider : How to load extra web.sitemap files from MEF-enabled module in MVC 4

我在 C# class 库项目中有一个单独的模块,它是通过 MEF 导入加载的。 作为将站点地图信息与模块一起使用的初步尝试,我添加了一个带有必要标记的 web.sitemap 文件,但我似乎无法清楚地了解如何加载它并将其附加到主机内存中的 MVC 项目站点地图。

我也尝试过使用 MvcSiteMapNode 属性,但还没有真正实现它。

首先,Attribute 和 SiteMap 哪个方法最容易使用?

其次,任何人都可以为我提供有关如何执行这些操作的指导吗?

我更喜欢使用站点地图文件,因为它应该避免依赖 MEF 模块中的 MvcSiteMapProvider。

您可以将 XML 嵌入到您的模块中,然后通过 MEF 以某种方式导出它们,我很确定这是一个选项。

要从内存加载 XML,您需要使用外部 DI 容器并自己实现 IXmlSource 接口。

public class MyXmlSource : IXmlSource
{
    public XDocument GetXml()
    {
        // Load the XML from wherever...
    }
}

那么DI配置只需要换出默认的XmlSource

var excludeTypes = new Type[] { 
    typeof(IXmlSource)
};

// More DI config not shown...

this.For<IXmlSource>()
    .Use<MyXmlSource>();

当然,如果你有多个文件,你需要多次注册IXmlSourceXmlSiteMapNodeProviderXmlSiteMapNodeProvider 只能合并根节点下的节点,所以你不能把它们放在 SiteMap 的任何地方。

XML 和属性是配置 MvcSiteMapProvider.

最不灵活的选项

另一种方法

最灵活的选择是 use ISiteMapNodeProvider implementations to load your configuration data which also requires an external DI container. The second-best option is to use dynamic node provider 实现,但存在的限制是它们不能包含根节点并且需要 XML 节点或 .NET 属性来托管提供程序。

但是,如果您不想要任何第 3 方依赖项,您将需要在您自己的基础库中定义的自定义抽象 (DTO),该基础库通过 MEF 导出,然后由 ISiteMapNodeProviderIDynamicNodeProvider 从抽象中加载数据。

public class SiteMapNodeDto
{
    public string Key { get; set; }
    public string ParentKey { get; set; }
    public string Title { get; set; }
    public IDictionary<string, object> RouteValues { get; set; }

    // Additional properties...
}

然后有一个你的模块可以实现的某种接口来提供节点。

public interface IModuleSiteMapNodeProvider
{
    IEnumerable<SiteMapNodeDto> GetNodes();
}

我对 MEF 的简短体验是几年前的事了,所以我不记得你是如何导出一个类型并将其导入到其他地方的,所以你需要自己解决这个问题。

然后在您的主应用程序中,您可以创建一个方法来将您的 DTO 转换为 MvcSiteMapProviderISiteMapNodeToParentRelationDynamicNode)所期望的类型。

public static SiteMapNodeProviderExtensions
{
    public static ISiteMapToParentRelation CreateNode(this ISiteMapNodeHelper helper, SiteMapNodeDto dto, string sourceName)
    {
         string key = helper.CreateNodeKey(
            dto.ParentKey,
            dto.Key,
            dto.Url,
            dto.Title,
            dto.Area,
            dto.Controller, 
            dto.Action, 
            dto.HttpMethod,
            dto.Clickable);

        var nodeParentMap = helper.CreateNode(key, attribute.ParentKey, sourceName);
        var node = nodeParentMap.Node;

        node.Title = title;

        // Populate remaining properties...

        return nodeParentMap;
    }
}

然后在 ISiteMapNodeProvider 中,您只需为每个节点调用此方法。

public IEnumerable<ISiteMapNodeToParentRelation> GetSiteMapNodes(ISiteMapNodeHelper helper)
{
    string sourceName = typeof(SiteMapNodeDto).Name;
    IEnumerable<SiteMapNodeDto> dtos = someExternalSource.GetNodes();

    foreach (var dto in dtos)
    {
        yield return helper.CreateNode(dto, sourceName);
    }
}

如果您想为您的模块开发人员提供 SiteMap 节点作为第一个 class 功能(并像使用 XML 一样真正轻松地理解节点的层次结构),您可以创建一个 Fluent API 以便您可以在代码中表达节点。看看 this pull request 中的一种方法。