parameters in routing do not work MVC 3

眉间皱痕 提交于 2020-01-04 03:58:01

问题


I am sure I am doing something wrong, but after spending a few hours on this with no luck, I would be really happy if someone can help me out with this.

Seems like the routing system honors the parameters only in the first routing registration.

This is how my global.asax.cs looks like

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcApplication4
{


    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                     "t", // Route name
                     "{controller}/{action}/{i}/{v}",  
                     new { i = UrlParameter.Optional, v = UrlParameter.Optional }  
                 );

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", 
                new {  id = UrlParameter.Optional } 
            );





        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

This is how the home controller looks like

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication4.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index(int? id)
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View();
        }

        public ActionResult About(int? a)
        {
            return View();
        }



    }
}

The problem is when I try this url

http://localhost:52230/Home/Index/2

The id is always null. But if I try http://localhost:52230/Home/Index?id=2 ....it works.

It also works if I register home/index before any other route. In which case the routes registered later have the same problem in accepting parameters.

What am I doing wrong here?

UPDATE:

I want both these controllers to work, how would my route registration look like?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication4.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index(int? id)
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View();
        }




    }
}

2nd controller

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication4.Controllers
{
    public class VisitorController : Controller
    {
        //
        // GET: /VisitorSecurityPoints/


        public ActionResult Test(string i,string v)
        {

            return View();
        }

    }
}

回答1:


The routes are ordered from specific to general. That means MVC will always try to match the most specific route when looking at the URL which has been requested. The routes will become more "greedy" the further down the route list they are.

If we take a closer look at the two routes in question, we can see that there is no way for MVC to differentiate between the two, unless the v parameter is supplied. They both have the controller and action parameters, and they both also have an optional third parameter. If v isn't supplied, MVC would have no way of knowing which route to use unless a priority system like this was in place, and that's why the order of the routes in the routing table is important.

There are ways to allow MVC to differentiate between two routes like this, but it depends on the data type of the parameter in question. For example, if i was a DateTime, rather than an int, you could add a Route Constraint which matched dates only. See this article for more information on constraints.

I also second Richard's advice for using RouteDebugger. It's invaluable for helping to understand situations such as this and can lead to cleaner routing table design.

Edit

I should also mention that the reason the URL "works" when you tag ?id=2 on the end is because MVC tries to model bind directly to matching action parameters in the query string. However, note that a parameter matching a route will take precedence over a value supplied in the query string. For example, using the following route:

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Navigating to http://localhost:50754/home/index/2 will result in id being 2.
Navigating to http://localhost:50754/home/index/?id=4 will result in id being 4.
Navigating to http://localhost:50754/home/index/2?id=4 will result in id being 2.

Updated after comments

The simplest way to solve your particular problem is to change the route table to include the following route:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "visitors", // Route name
        "visitor/{action}/{i}/{v}", // URL with parameters
        new
        {
            controller = "Visitor", action = "Test",
            i = UrlParameter.Optional, v = UrlParameter.Optional
        }
    );

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

Notice the {action} parameter is still present in this new route. This makes things a little easier to expand on it to cater for other actions in the controller. If you need to constrain the route to the actions that are present on the controller, you'd need to add a route constraint as mentioned earlier.

One caveat to this approach is that the route table can grow quite quickly if you're constantly specifiying new routes to match a few URLs. That can make adding new features to a site more difficult because of the existing routing and can also make maintenance more difficult. Whenever possible, you should try to design a route to match the default {controller}/{action}/{id} route because it makes maintenance and debugging so much easier in the long run.




回答2:


I believe its because your other route ("t") matches first.




回答3:


You can check which routes are being matched by using RouteDebugger. Just install it using nuget:

PM> install-package RouteDebugger

When you view the page it'll list all of your routes and indicate which one(s) were matched. The first matched route will be used.



来源:https://stackoverflow.com/questions/11819989/parameters-in-routing-do-not-work-mvc-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!