【问题标题】:MVC Specify Actions with Querystring Params instead of "/" foldersMVC 使用查询字符串参数而不是“/”文件夹指定操作
【发布时间】:2018-06-21 04:47:36
【问题描述】:

在 MVC6 中,有没有办法将我的 URL 中的操作指定为查询字符串而不是路径?

例如http://localhost/Index2 和 http://localhost/Edit

这两个都分别触发了我的控制器中的 Index2 和 Edit 操作。但我正在使用一个网站,我们只允许有一个 URL(长篇故事)......所以可以通过导航到相应的 URL 来触发完全相同的操作,例如

http://localhost/Default.aspx?action=Index2 和 http://localhost/Default.aspx?action=Edit

我想我能做的就是在我的控制器中获取十几个操作函数并将它们全部组合到索引操作中,并基于“操作”查询字符串参数,执行 switch/case-select 语句并复制每个在每个 CASE 下,将原始动作/subs 放入它们各自的块中。但我希望可以做一些看起来更干净的事情。

仅供参考:我不会将查询字符串用于其他任何事情。我所有的价值观都是通过 POSTS 从一个动作传递到另一个动作

【问题讨论】:

    标签: asp.net-mvc url-rewriting


    【解决方案1】:

    是的,您使用 Route 装饰器,但不是添加路由字符串,而是添加一个空字符串。示例:

    namespace TestAPI.Controllers
    {
        [RoutePrefix("api/testapi")] // eg: http://localhost/api/testapi?param1=foo&param2=bar
        public class TestAPIController : BaseAPIController
        {
            [HttpGet]
            [Route("")] // so that ASP MVC recognizes query strings
            public HttpResponseMessage Get()
            {
    
                // get the query parameters into a collection
                var queryparams = Request.GetQueryNameValuePairs().Select(q => new { q.Key, q.Value });
    
    
                // declare main keys value pairs
                string param1 = queryparams.Where(k => k.Key == "param1").Select(v => v.Value).FirstOrDefault();
                string param2 = queryparams.Where(k => k.Key == "param2").Select(v => v.Value).FirstOrDefault();
    
                // Do your stuff
    
                // Return a response
    
    
            }
        }
    }
    

    【讨论】:

    • 由于我的操作目前正在通过 post 接受参数,并且您在那里有 [HttpGet] 属性,这仍然有效吗?为了继续接收已发布的字段,我必须将您的示例更改为 [HttpPost](同时仍收集查询字符串以获取操作名称)
    • 糟糕,抱歉,我没看到。是的,将其更改为[HttpPost] 应该可以。我认为您还需要将方法调用更改为 public HttpResponseMessage Post([FromUri]param1 value)
    【解决方案2】:

    通过继承RouteBase,这种事情很容易做到。它允许您使用几乎任何您想要分析请求的逻辑,并根据请求中的内容将其定向到特定的操作方法。

    这是一条使用http://localhost/Default.aspx?action=Index2 和http://localhost/Default.aspx?action=Edit 示例的路线

    public class CustomRoute : RouteBase
    {
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            RouteData result = null;
    
            // Trim off the leading "/"
            var path = httpContext.Request.Path.Substring(1);
    
            if (path.Equals("Default.aspx", StringComparison.OrdinalIgnoreCase))
            {
                result = new RouteData(this, new MvcRouteHandler());
    
                result.Values["controller"] = "Home";
                result.Values["action"] = httpContext.Request.QueryString["action"] ?? "Index";
            }
    
            // IMPORTANT: Returning null tells the routing framework to try
            // the next registered route.
            return result;
        }
    
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            // Returning null skips this route.
            // Alternatively, implement a scheme to turn the values passed here
            // into a URL. This will be used by UrlHelper to build URLs in views.
            return null;
        }
    }
    

    可以像这样用MVC注册。

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.Add(new CustomRoute());
    
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                namespaces: new string[] { "WebApplication23.Controllers" }
            );
        }
    }
    

    请注意,已注册的订单路线很重要。

    如果您坚持使用filename.extension 模式,还有一件事 - 您必须配置 IIS 以允许请求到达 MVC,因为默认情况下为 any URL with a . in it will throw a 404 not found error。

    <system.webServer>
      <handlers>
        <add name="ApiURIs-ISAPI-Integrated-4.0"
          path="/Default.aspx"
          verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
          type="System.Web.Handlers.TransferRequestHandler"
          preCondition="integratedMode,runtimeVersionv4.0" />
      </handlers>
    </system.webServer>
    

    【讨论】:

    • 其实“.aspx”不是必需的。我只是随意地把它扔在那里。我试试看
    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 2015-05-06
    • 2016-11-25
    • 2018-09-30
    • 1970-01-01
    • 2011-11-15
    相关资源
    最近更新 更多