草庐IT

c# - 我怎样才能遍历所有路线?

coder 2024-05-27 原文

在 mvc (2) 用户控件中,我想遍历所有路由值。

所以如果我有这样的 Controller :

UserController
AccountController

我需要一组将出现在 url 中的值,例如:

/user/...
/account/...

即值用户、帐户。

我怎样才能得到这个?

我尝试了 RouteTables 但无法弄清楚。

最佳答案

哦,真是个好问题,可以让我自己忙上一个小时。 为了实现所需的功能,我们需要连接到 MVC 源代码和一点反射。

  1. 默认情况下,路由名称是不可用的,因此我们需要编写一个路由集合扩展,以将路由名称保存在 RouteData token 中。

    public static Route MapRouteWithName(this RouteCollection routes,string name, string   url, object defaults=null, object constraints=null)
    {
    
    Route route = routes.MapRoute(name, url, defaults, constraints);
    route.DataTokens = new RouteValueDictionary();
    route.DataTokens.Add("RouteName", name);
    return route;
    }
    
  2. 修改 global.asax maproute 调用以调用先前的扩展

    routes.MapRouteWithName(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
    
  3. 稍微修改了 MVC PathHelper。(在项目中包含这个助手)

    using System;
    using System.Collections.Specialized;
    using System.Web;
    
    public static class PathHelpers
    {
    
    // this method can accept an app-relative path or an absolute path for contentPath
    public static string GenerateClientUrl(HttpContextBase httpContext, string contentPath)
    {
        if (String.IsNullOrEmpty(contentPath))
        {
            return contentPath;
        }
    
        // many of the methods we call internally can't handle query strings properly, so just strip it out for
        // the time being
        string query;
        contentPath = StripQuery(contentPath, out query);
    
        return GenerateClientUrlInternal(httpContext, contentPath) + query;
    }
    
    private static string GenerateClientUrlInternal(HttpContextBase httpContext, string contentPath)
    {
        if (String.IsNullOrEmpty(contentPath))
        {
            return contentPath;
        }
    
        // can't call VirtualPathUtility.IsAppRelative since it throws on some inputs
        bool isAppRelative = contentPath[0] == '~';
        if (isAppRelative)
        {
            string absoluteContentPath = VirtualPathUtility.ToAbsolute(contentPath, httpContext.Request.ApplicationPath);
            string modifiedAbsoluteContentPath = httpContext.Response.ApplyAppPathModifier(absoluteContentPath);
            return GenerateClientUrlInternal(httpContext, modifiedAbsoluteContentPath);
        }
    
        string relativeUrlToDestination = MakeRelative(httpContext.Request.Path, contentPath);
        string absoluteUrlToDestination = MakeAbsolute(httpContext.Request.RawUrl, relativeUrlToDestination);
        return absoluteUrlToDestination;
    }
    
    public static string MakeAbsolute(string basePath, string relativePath)
    {
        // The Combine() method can't handle query strings on the base path, so we trim it off.
        string query;
        basePath = StripQuery(basePath, out query);
        return VirtualPathUtility.Combine(basePath, relativePath);
    }
    
    public static string MakeRelative(string fromPath, string toPath)
    {
        string relativeUrl = VirtualPathUtility.MakeRelative(fromPath, toPath);
        if (String.IsNullOrEmpty(relativeUrl) || relativeUrl[0] == '?')
        {
            // Sometimes VirtualPathUtility.MakeRelative() will return an empty string when it meant to return '.',
            // but links to {empty string} are browser dependent. We replace it with an explicit path to force
            // consistency across browsers.
            relativeUrl = "./" + relativeUrl;
        }
        return relativeUrl;
    }
    
    private static string StripQuery(string path, out string query)
    {
        int queryIndex = path.IndexOf('?');
        if (queryIndex >= 0)
        {
            query = path.Substring(queryIndex);
            return path.Substring(0, queryIndex);
        }
        else
        {
            query = null;
            return path;
        }
    }
    
    }
    
  4. 在 Controller 中添加一些辅助方法

    public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteCollection routeCollection, RequestContext requestContext)
    {
    
        RouteValueDictionary mergedRouteValues = MergeRouteValues(actionName, controllerName);
    
        VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues);
        if (vpd == null)
        {
            return null;
        }
    
        string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath);
        return modifiedUrl;
    }
    public static RouteValueDictionary MergeRouteValues(string actionName, string controllerName)
    {
        // Create a new dictionary containing implicit and auto-generated values
        RouteValueDictionary mergedRouteValues = new RouteValueDictionary();
    
        // Merge explicit parameters when not null
        if (actionName != null)
        {
            mergedRouteValues["action"] = actionName;
        }
    
        if (controllerName != null)
        {
            mergedRouteValues["controller"] = controllerName;
        }
    
        return mergedRouteValues;
    }
    
  5. 现在我们可以编写一些反射逻辑来读取 Controller 、操作和路由名称。

    Dictionary<string, List<string>> controllersAndActions = new Dictionary<string, List<string>>();
    
    // Get all the controllers
    var controllers = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Controller).IsAssignableFrom(t));
    
    foreach (var controller in controllers)
    {
        List<string> actions = new List<string>();
        //Get all methods without HttpPost and with return type action result
        var methods = controller.GetMethods().Where(m => typeof(ActionResult).IsAssignableFrom(m.ReturnType)).Where(a=>!a.GetCustomAttributes(typeof(HttpPostAttribute),true).Any());
        methods.ToList().ForEach(a => {
            actions.Add(a.Name);
        });
        var controllerName = controller.Name;
        if (controllerName.EndsWith("Controller"))
        {
            var nameLength = controllerName.Length - "Controller".Length;
            controllerName = controllerName.Substring(0, nameLength);
        }
        controllersAndActions.Add(controllerName, actions);
    }
    List<string> allowedRoutes = new List<string>();
    
    var routeNames = RouteTable.Routes.Where(o=>o.GetRouteData(this.HttpContext)!=null).Select(r=>r.GetRouteData(this.HttpContext).DataTokens["RouteName"].ToString());
    foreach (var cName in controllersAndActions)
    {
        foreach (var aName in cName.Value)
        {
            foreach (var item in routeNames)
            {
                allowedRoutes.Add(GenerateUrl(item, aName, cName.Key, RouteTable.Routes, this.Request.RequestContext));
            }
        }
    
    }
    
  6. 要记住的要点:如果您在路由中定义了任何默认参数,那么这些 Controller 和操作的 url 将为空。例如在上面的示例中,“/Home/Index”将显示为“/”

  7. 下载示例应用程序 Link To Download

关于c# - 我怎样才能遍历所有路线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9231604/

有关c# - 我怎样才能遍历所有路线?的更多相关文章

  1. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  4. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  5. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  6. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. 怎样用一台手机做自媒体? - 2

    其实做自媒体的成本并不高,入门只需要一部手机即可!在手机上找视频素材、使用手机剪辑视频、最后使用手机发布视频作品获得收益!方法并不难,今天这期内容就来给粉丝们分享一种小方法,每天稳定收益100-300,抓紧点赞收藏!1、找素材(1)使用手机拍摄自己喜欢的经典段落,使用程序把文案内容提取出来(2)也可以在豆瓣、知乎、微博等网站中找一些自己需要的文案素材(3)把文案进行润色修改,可以加入一些自己的观点(4)视频素材可以使用软件中自带的素材,也可以在素材网站中下载完整版的素材2、文案配音(1)把复制好的文案直接导入小程序中(2)调整音色、音调后一键合成音频即可(3)可以选择自己朗读配音,需要花一点时

  10. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

随机推荐