MVC 自定义路由中的多个级别

2023-11-24

我正在尝试构建自己的小cms。我创建了一个抽象 pageBase 类,由 Static、Reviews、Articles、News 继承。每个都有自己的控制器方法。

我的问题是我需要允许管理员定义他自己的自定义路径级别。例如。news\local\mynewdog or Articles\events\conventions\mycon。所以我想要一种传递字符串数组并设置自定义路由的方法。


您可以使用自定义无缝制作 CMS 风格的路线RouteBase子类。

public class PageInfo
{
    // VirtualPath should not have a leading slash
    // example: events/conventions/mycon
    public string VirtualPath { get; set; }
    public Guid Id { get; set; }
}

public class CustomPageRoute
    : RouteBase
{
    private object synclock = new object();

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        RouteData result = null;

        // Trim the leading slash
        var path = httpContext.Request.Path.Substring(1);

        // Get the page that matches.
        var page = GetPageList(httpContext)
            .Where(x => x.VirtualPath.Equals(path))
            .FirstOrDefault();

        if (page != null)
        {
            result = new RouteData(this, new MvcRouteHandler());

            // Optional - make query string values into route values.
            this.AddQueryStringParametersToRouteData(result, httpContext);

            // TODO: You might want to use the page object (from the database) to
            // get both the controller and action, and possibly even an area.
            // Alternatively, you could create a route for each table and hard-code
            // this information.
            result.Values["controller"] = "CustomPage";
            result.Values["action"] = "Details";

            // This will be the primary key of the database row.
            // It might be an integer or a GUID.
            result.Values["id"] = page.Id;
        }

        // IMPORTANT: Always return null if there is no match.
        // This tells .NET routing to check the next route that is registered.
        return result;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        VirtualPathData result = null;

        PageInfo page = null;

        // Get all of the pages from the cache.
        var pages = GetPageList(requestContext.HttpContext);

        if (TryFindMatch(pages, values, out page))
        {
            if (!string.IsNullOrEmpty(page.VirtualPath))
            {
                result = new VirtualPathData(this, page.VirtualPath);
            }
        }

        // IMPORTANT: Always return null if there is no match.
        // This tells .NET routing to check the next route that is registered.
        return result;
    }

    private bool TryFindMatch(IEnumerable<PageInfo> pages, RouteValueDictionary values, out PageInfo page)
    {
        page = null;
        Guid id = Guid.Empty;

        // This example uses a GUID for an id. If it cannot be parsed,
        // we just skip it.
        if (!Guid.TryParse(Convert.ToString(values["id"]), out id))
        {
            return false;
        }

        var controller = Convert.ToString(values["controller"]);
        var action = Convert.ToString(values["action"]);

        // The logic here should be the inverse of the logic in 
        // GetRouteData(). So, we match the same controller, action, and id.
        // If we had additional route values there, we would take them all 
        // into consideration during this step.
        if (action == "Details" && controller == "CustomPage")
        {
            page = pages
                .Where(x => x.Id.Equals(id))
                .FirstOrDefault();
            if (page != null)
            {
                return true;
            }
        }
        return false;
    }

    private void AddQueryStringParametersToRouteData(RouteData routeData, HttpContextBase httpContext)
    {
        var queryString = httpContext.Request.QueryString;
        if (queryString.Keys.Count > 0)
        {
            foreach (var key in queryString.AllKeys)
            {
                routeData.Values[key] = queryString[key];
            }
        }
    }

    private IEnumerable<PageInfo> GetPageList(HttpContextBase httpContext)
    {
        string key = "__CustomPageList";
        var pages = httpContext.Cache[key];
        if (pages == null)
        {
            lock(synclock)
            {
                pages = httpContext.Cache[key];
                if (pages == null)
                {
                    // TODO: Retrieve the list of PageInfo objects from the database here.
                    pages = new List<PageInfo>()
                    {
                        new PageInfo() 
                        { 
                            Id = new Guid("cfea37e8-657a-43ff-b73c-5df191bad7c9"), 
                            VirtualPath = "somecategory/somesubcategory/content1" 
                        },
                        new PageInfo() 
                        { 
                            Id = new Guid("9a19078b-2d7e-4fc6-ae1d-3e76f8be46e5"), 
                            VirtualPath = "somecategory/somesubcategory/content2" 
                        },
                        new PageInfo() 
                        { 
                            Id = new Guid("31d4ea88-aff3-452d-b1c0-fa5e139dcce5"), 
                            VirtualPath = "somecategory/somesubcategory/content3" 
                        }
                    };

                    httpContext.Cache.Insert(
                        key: key, 
                        value: pages, 
                        dependencies: null, 
                        absoluteExpiration: System.Web.Caching.Cache.NoAbsoluteExpiration, 
                        slidingExpiration: TimeSpan.FromMinutes(15), 
                        priority: System.Web.Caching.CacheItemPriority.NotRemovable, 
                        onRemoveCallback: null);
                }
            }
        }

        return (IEnumerable<PageInfo>)pages;
    }
}

您可以像这样向 MVC 注册路由。

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

// Case sensitive lowercase URLs are faster. 
// If you want to use case insensitive URLs, you need to
// adjust the matching code in the `Equals` method of the CustomPageRoute.
routes.LowercaseUrls = true;

routes.Add(
    name: "CustomPage", 
    item: new CustomPageRoute());

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

以上假设您有一个CustomPageController with a Details动作方法。

public class CustomPageController : Controller
{
    public ActionResult Details(Guid id)
    {
        // Do something with id

        return View();
    }
}

如果您希望它转到不同的控制器操作(甚至使它们成为构造函数参数),您可以更改路线。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MVC 自定义路由中的多个级别 的相关文章

随机推荐

  • 在 C# 中同步包装异步方法

    我有一个第三方库 其中包含一个异步执行函数的类 该类继承自Form 该函数基本上根据数据库中存储的数据执行计算 一旦完成 它就会在调用表单中调用 Complete 事件 我想做的是从非 Windows 表单应用程序同步调用该函数 问题是 无
  • C++ 数组删除运算符语法

    我做完之后说 Foo array new Foo N 我一直都是这样删除的 delete array 然而 有时我会这样看 delete N array 由于它似乎可以编译并工作 至少在 msvc2005 中 我想知道 正确的做法是什么 那
  • Spring + Hibernate:具有相同标识符值的不同对象已与会话关联

    在我使用 Spring 和 Hibernate 的应用程序中 我解析 CSV 文件并通过调用填充数据库handleRow 每次从 CSV 文件读取一条记录时 我的域模型 家族 有很多 子家族 亚科 有很多 轨迹 轨迹 属于 物种 Famil
  • Android:我可以一个接一个地显示多个对话框吗?有没有类似Dialog Z-Level 的东西?

    是否可以一个接一个地显示多个对话框 有没有类似Dialog Z Level 的东西 我正在使用 DialogFragment 用户在其中选择元素 当他确认他的选择时 它会保存到数据库并发送到服务器上 如果保存操作失败 我想通知用户 另一个对
  • 如何一起使用 Angular 1.3.4 和 Angular 2 [重复]

    这个问题在这里已经有答案了 我已经有一个基于 Angular 1 3 4 构建的应用程序 我想将其更改为 Angular 2 但模块明智 假设我的页面上有 5 个模块 我想将一个模块迁移到 Angular 2 其他模块应该像以前的 1 3
  • 将下拉菜单选择保存在 cookie 中?

    我已经看过这个帖子好几次了 但我根本无法让代码工作 我需要帮助让这个下拉菜单将其设置保存到 cookie 这样当用户再次访问该网站时 他们之前的选择就会被保留 落下
  • Snakemake:使用run指令时如何实现log指令?

    Snakemake 允许为每个规则创建日志log参数指定日志文件的名称 通过管道传输结果相对简单shell输出到此日志 但我无法找出记录输出的方法run输出 即 python 脚本 一种解决方法是将 python 代码保存在脚本中 然后从
  • 链接服务器性能和选项

    在工作中 我们有两台服务器 其中一台正在运行很多人使用的应用程序 该应用程序具有 SQL Server 2000 后端 我很长时间以来都可以自由地查询它 但无法向其中添加任何内容 例如存储过程或额外的表 这导致我们将第二个 SQL Serv
  • 为什么 std::reference_wrapper 在调用成员函数时不隐式转换为引用? [复制]

    这个问题在这里已经有答案了 我不明白为什么不能使用std reference wrapper像这样 include
  • 开发 iPhone 应用程序以在 iPad 上运行 - 自动设置 2x

    有没有一种方法可以以编程方式将 iPad 设置为在 iPhone 应用程序启动时以 2 倍的速度运行 但仍保持 iPhone 应用程序本机 我知道我可以为每个硬件平台创建 NIB 文件 但为了方便起见 我只是希望应用程序启动就像用户在 iP
  • Scheme 可以将列表扩展为参数吗?

    考虑到我有一个程序 plus x y 女巫正好需要两个参数 现在我还有一个列表 其中包含两个对象 例如 list 1 2 那么 如果有any将列表扩展为两个参数的神奇方法 我们有一个点概念版本 但是那个isn t我想要的是 我只是想扩展该列
  • 在 Eclipse 中打开 xml 文件时出现错误 [重复]

    这个问题在这里已经有答案了 在 Eclipse 中 当我打开具有相同数据的两个不同名称的 xml 文件 意味着 A 和 B 是 2 个 xml 文件 它们具有相同的数据 时 我在控制台中出现错误 我在控制台中收到以下错误 为什么会出现这个错
  • 如何将 buildapp 与 Quicklisp 结合使用

    我想使用 buildapp 来制作作为给出的curl lisp可执行文件example buildapp output lisp curl asdf path src clbuild systems load system drakma e
  • 自动发布回到 mvc 下拉列表中

    要求 我的视图页面上有一个下拉列表 显示供应商列表 从下拉列表中选择供应商后 页面将显示所选供应商的详细信息 默认情况下 我需要选择第一个供应商并显示其详细信息 我可以使用以下代码来完成此任务 问题 不知道如何实现自动回发 true在 MV
  • 我可以在一个 Web 应用程序中拥有两个 web.xml 文件吗?

    我可以拥有一个包含多个 web xml 文件的应用程序吗 并且两个应用程序可以有父子关系从而有两个web xml吗 对于低于 servlet 3 0 的版本 则不能 如果您使用的是 3 0 则有一个可能性 在 JSR 315 Java Se
  • Azure Powershell:获取服务的公共虚拟IP

    是否可以使用 powershell 获取 azure 服务的公共虚拟 IP VIP 一种方法是使用 Get AzureEndpoint 命令 Get AzureVM Name thevmname ServiceName theservice
  • 面向对象的c++ win32?

    我想创建自己的类来处理创建窗口和窗口过程 但我注意到窗口过程必须是静态的 我现在想知道是否可以使窗口过程面向对象 我读过一些关于面向对象窗口的教程 但它们总是使过程静态 那有什么用 任何有关如何解决此问题的链接或信息将不胜感激 thanks
  • 如何在数据库中存储图像的位置?

    我有一个颜色列表 其中包含我想要向特定用户显示的纹理 因此我需要加载特定用户拥有的颜色的图像 颜色的信息包含在 ObjecDTO 中 其中一个属性是其图像小路 我的问题是我应该如何在数据库中存储图像路径 是否有任何特殊规则 例如 由于数据库
  • Spring Batch“默认”上下文变量是什么?

    In the 春季批次步进范围文档 存在三个无法解释的 spring batch 上下文映射 jobParameters jobExecutionContext and stepExecutionContext Springsource示例
  • MVC 自定义路由中的多个级别

    我正在尝试构建自己的小cms 我创建了一个抽象 pageBase 类 由 Static Reviews Articles News 继承 每个都有自己的控制器方法 我的问题是我需要允许管理员定义他自己的自定义路径级别 例如 news loc