asp.net-mvc - 将 MvcSiteMapProvider 与属性和属性路由结合使用

标签 asp.net-mvc asp.net-mvc-5 asp.net-mvc-routing mvcsitemapprovider

我正在尝试在 ASP.Net MVC 5 应用程序中使用 MVCSiteMapProvider。可以找到很多资源和教程,但其中大多数是关于基于 XML 的配置。

在我的应用程序中,属性路由已被使用,我想将 MvcSiteMapProvider 与属性一起使用,但是关于这种组合的资源不足,我遇到了一些问题。

例如,我有如下三个操作:

//HomeController    
    [Route(@"~/home", Name = "CustomerHomeIndex")]
        [MvcSiteMapNode(Title = "Home Page",  Key = "Home")] 
        public ActionResult Index() {
            return View()
        }

//AccountController       
        [Route(@"~/account", Name = "AccountIndex")]
        [MvcSiteMapNode(Title = "Accounts", ParentKey = "Home", Key = "AccountIndex")] 
        public ActionResult Index() {
        // fetching records from database
            return View();
        }

        [Route(@"~/account-management/{id:int}/{domain:regex(^([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$)}", Name = "AccountDetail")]
        [MvcSiteMapNode(Title = "Account Detail", ParentKey = "AccountIndex", Key = "AccountDetail")] 
        public ActionResult Details(string domain, int id) {
        // fetching record from database by parameters
            return View();
        }

我还在我的 View 中添加了 SiteMapPath 代码

//Details.cshtml
    @Html.MvcSiteMap().SiteMapPath()

但是没有显示任何结果。在我看来,它与 preservedRouteParameters 有关,但我找不到有关具有属性路由的 MvcSiteMapNode 属性中使用的此参数的任何信息。

实际上我还有一个关于本地化的问题,我想从资源文件中获取标题,所有内容都已经存在于全局资源文件中。我读过一些有关本地化支持的内容,但它们也与基于 XML 的配置相关。

最佳答案

默认情况下,XML 和 .NET 属性的提供程序均已启用。在此配置中,根节点(没有父键的节点)必须放置在 XML 文件中。要仅使用 .NET 属性而不在 XML 中进行任何配置,您需要从配置中删除 XML 节点提供程序。

内部DI:

<appSettings>
    <add key="MvcSiteMapProvider_EnableSiteMapFile" value="false"/>
</appSettings>

外部 DI(所示为 StructureMap 示例):

// Register the sitemap node providers
var siteMapNodeProvider = this.For<ISiteMapNodeProvider>().Use<CompositeSiteMapNodeProvider>()
    .EnumerableOf<ISiteMapNodeProvider>().Contains(x =>
    {
        //Remove the XmlSiteMapNodeProvider
        //x.Type<XmlSiteMapNodeProvider>()
        //    .Ctor<bool>("includeRootNode").Is(true)
        //    .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
        //    .Ctor<IXmlSource>().Is(xmlSource);
        x.Type<ReflectionSiteMapNodeProvider>()
            .Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan)
            .Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
    });

您还需要确保带有 Controller 的程序集包含在 IncludeAssembliesForScan 配置设置中。请注意,NuGet 包自动包含您安装 MvcSiteMapProvider 的程序集,因此,如果您的 Controller 全部位于主 MVC 项目中,则无需触及此程序集。

内部DI:

<appSettings>
    <add key="MvcSiteMapProvider_IncludeAssembliesForScan" value="MyAssembly,MyOtherAssembly"/>
</appSettings>

外部DI:

string[] includeAssembliesForScan = new string[] { "MyAssembly", "MyOtherAssembly" };

... Other code omitted ...

// Register the sitemap node providers
var siteMapNodeProvider = this.For<ISiteMapNodeProvider>().Use<CompositeSiteMapNodeProvider>()
    .EnumerableOf<ISiteMapNodeProvider>().Contains(x =>
    {
        //Remove the XmlSiteMapNodeProvider
        //x.Type<XmlSiteMapNodeProvider>()
        //    .Ctor<bool>("includeRootNode").Is(true)
        //    .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
        //    .Ctor<IXmlSource>().Is(xmlSource);
        x.Type<ReflectionSiteMapNodeProvider>()
            .Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan) // <- Setting is injected here
            .Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
    });

您无需做任何特殊操作即可使其与 AttributeRouting 一起使用 - MvcSiteMapProvider 会自动选取这些路由,因此只要您正确配置它们并在 MVC 中工作,它就应该可以正常工作。

是的,您可能确实需要对包含自定义参数的操作使用 PreservedRouteParameters,如下所示。

[Route(@"~/account-management/{id:int}/{domain:regex(^([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$)}", Name = "AccountDetail")]
[MvcSiteMapNode(Title = "Account Detail", ParentKey = "AccountIndex", Key = "AccountDetail", PreservedRouteParameters="domain,id")] 
public ActionResult Details(string domain, int id) {
// fetching record from database by parameters
    return View();
}

在您的简单示例中,这可以正常工作。但是,您需要充分了解servedRouteParameters 的工作原理,以便在嵌套超出第一个节点的节点级别时正确使用它们。您不能使用具有相同键名称但具有不同含义的参数,这些参数在同一请求中都可见,因为 MvcSiteMapProvider 始终将当前请求中的值插入到具有匹配键名称的所有节点中。您还必须在(子节点的)请求中提供祖先节点所需的任何键,以便导航正常工作。请参阅How to Make MvcSiteMapProvider Remember a User's Position和演示代码以获取完整的详细信息。

请参阅 reading localization from an external assembly 。但是,请注意,从 v4.6.15 开始,唯一可能的方法是使用外部 DI 容器来注入(inject)自定义 IStringLocalizer。

默认本地化实现仅支持放入 App_GlobalResources 文件夹中的文件。请注意,这是 problematic with MVC因为添加这些文件时的默认设置使它们以无法从 MVC 访问的方式进行编译。我们目前是gathering requirements to make a new extension point允许从备用位置配置资源。

关于asp.net-mvc - 将 MvcSiteMapProvider 与属性和属性路由结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25682481/

相关文章:

c# - 中间带有属性路由的 Web Api 可选参数

asp.net - 在 url 中手动使用 Web api 方法

asp.net-mvc - 在 MVC3 页面中包含 RenderPartial 的开销是多少

c# - ASP.NET MVC 使用 UIHint 属性生成 DropDownList

c# - 限制访问,直到用户确认电子邮件链接

c# - 从客户端到服务器共享 facebook session token

asp.net-mvc-3 - 适本地形成一个通用的、RESTful 的路由方案

asp.net-mvc - MVC4 : How to sort this selectlist/dropdownlist

c# - 返回文件或 View 的方法

c# - 在浏览器关闭时更新数据库