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>();
当然,如果你有多个文件,你需要多次注册IXmlSource
和XmlSiteMapNodeProvider
。 XmlSiteMapNodeProvider
只能合并根节点下的节点,所以你不能把它们放在 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 导出,然后由 ISiteMapNodeProvider
或 IDynamicNodeProvider
从抽象中加载数据。
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 转换为 MvcSiteMapProvider
(ISiteMapNodeToParentRelation
或 DynamicNode
)所期望的类型。
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 中的一种方法。
我在 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>();
当然,如果你有多个文件,你需要多次注册IXmlSource
和XmlSiteMapNodeProvider
。 XmlSiteMapNodeProvider
只能合并根节点下的节点,所以你不能把它们放在 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 导出,然后由 ISiteMapNodeProvider
或 IDynamicNodeProvider
从抽象中加载数据。
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 转换为 MvcSiteMapProvider
(ISiteMapNodeToParentRelation
或 DynamicNode
)所期望的类型。
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 中的一种方法。