How to convert query string parameters to route in

2019-04-13 07:25发布

问题:

I have a blogging system that I'm building and I can't seem to get ASP.NET MVC to understand my route.

the route I need is /blogs/student/firstname-lastname so /blogs/student/john-doe, which routes to a blogs area, student controller's index action, which takes a string name parameter.

Here is my route

routes.MapRoute(
    name: "StudentBlogs",
    url: "blogs/student/{name}",
    defaults: new { controller = "Student", action="Index"}
);

My controller action

public ActionResult Index(string name)
{
    string[] nameparts = name.Split(new char[]{'-'});
    string firstName = nameparts[0];
    string lastName = nameparts[1];

    if (nameparts.Length == 2 && name != null)
    {
      // load students blog from database
    }
    return RedirectToAction("Index", "Index", new { area = "Blogs" });            
}

But it won't seem to resolve...it works fine with /blogs/student/?name=firstname-lastname, but not using the route I want, which is /blogs/student/firstname-lastname. Any advice on how to fix this would be greatly appreciated.

My RouteConfig

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

        routes.MapRoute(
         name: "StudentBlogs",
         url: "blogs/student/{name}",
         defaults: new { controller = "Student", action = "Index"},
         constraints: new { name = @"[a-zA-Z-]+" },
          namespaces: new string[] { "IAUCollege.Areas.Blogs.Controllers" }
     );

        routes.MapRoute(
            name: "Sitemap",
            url :"sitemap.xml",
            defaults: new { controller = "XmlSiteMap", action = "Index", page = 0}
        );

        //CmsRoute is moved to Gloabal.asax

        // campus maps route
        routes.MapRoute(
            name: "CampusMaps",
            url: "locations/campusmaps",
            defaults: new { controller = "CampusMaps", action = "Index", id = UrlParameter.Optional }
        );


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

        // error routes
        routes.MapRoute(
            name: "Error",
            url: "Error/{status}",
            defaults: new { controller = "Error", action = "Error404", status = UrlParameter.Optional }
        );


        // Add our route registration for MvcSiteMapProvider sitemaps
        MvcSiteMapProvider.Web.Mvc.XmlSiteMapController.RegisterRoutes(routes);
    }
}

回答1:

You have to declare custom routes before the default routes. Otherwise it will be mapping to {controller}/{action}/{id}.


Global.asax typically looks like this:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

If you created an Area named Blogs, there is a corresponding BlogsAreaRegistration.cs file that looks like this:

public class BlogsAreaRegistration : AreaRegistration 
{
    public override string AreaName 
    {
        get 
        {
            return "Blogs";
        }
    }

    public override void RegisterArea(AreaRegistrationContext context) 
    {
        context.MapRoute(
            "Admin_default",
            "Blogs/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }
        );
    }
}

Hyphens are sometimes treated like forward slashes in routes. When you are using the route blogs/students/john-doe, my guess is that it is matching the Area pattern above using blogs/students/john/doe, which would result in a 404. Add your custom route to the BlogsAreaRegistration.cs file above the default routes.



回答2:

Try adding the parameter to the route:

routes.MapRoute(
    name: "StudentBlogs",
    url: "blogs/student/{name}",
    defaults: new { controller = "Student", action="Index", name = UrlParameter.Optional}
);


回答3:

Try adding a constraint for the name parameter:

routes.MapRoute(
    name: "StudentBlogs",
    url: "blogs/student/{name}",
    defaults: new { controller = "Student", action="Index" },
    constraints: new { name = @"[a-zA-Z-]+" }
);

Dashes are a bit weird in MVC at times.. because they are used to resolve underscores. I will remove this answer if this doesn't work (although.. it should).

This has the added benefit of failing to match the route if a URL such as /blogs/student/12387 is used.

EDIT:

If you have controllers with the same name.. you need to include namespaces in both of your routes in each area. It doesn't matter where the controllers are.. even if in separate areas.

Try adding the appropriate namespace to each of the routes that deal with the Student controller. Somewhat like this:

routes.MapRoute(
    name: "StudentBlogs",
    url: "blogs/student/{name}",
    defaults: new { controller = "Student", action="Index" },
    namespaces: new string[] { "Website.Areas.Blogs.Controllers" }
);

..and perhaps Website.Areas.Admin.Controllers for the one in the admin area.