Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Routing wrong access the action

By default for URL routing in MVC is {controller}/{action}/{id}. Then we can access mydomain.com/Products/Details/1 and etc.

Now, I have register another map route I called CategoryLandingPage.

routes.MapRoute(
name: "CategoryLandingPage",
url: "category",
defaults: new { controller = "Category", action = "Index" }); 

So it will show all the category in the page.

Then I register another map route called CategoryDetails

routes.MapRoute(
name: "CategoryDetails", 
url: "category/{categoryName}", 
defaults: new { controller = "Category", action = "Details", categoryName = UrlParameter.Optional });

When somebody access mydomain.com/category/cars, it will show all the products with related to the cars.

Same controller also have another actions such Create,Edit,Delete, and more.

The problems is,When I access mydomain.com/category/create it will go to the Details action. It not go to the create action in Category Contoller.

How can I solved this matter?

like image 503
Azri Zakaria Avatar asked Jul 14 '15 17:07

Azri Zakaria


2 Answers

Two ways:

Either use a Route Constraint to ensure the {categoryName} part is a match for one of your categories:

//You will have to make this
var categoryRouteConstraint = new CategoryRouteConstraint();

routes.MapRoute(
name: "CategoryDetails", 
url: "category/{categoryName}", 
constraints: new { categoryName = categoryRouteConstraint }
defaults: new { controller = "Category", action = "Details", categoryName = UrlParameter.Optional });

Example route constraint:

public class CategoryRouteConstraint : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (routeDirection == RouteDirection.UrlGeneration)
                return true;

            if (string.Equals(parameterName, "categoryName", StringComparison.OrdinalIgnoreCase))
            {
                //return true if (string)values[parameterName] == "known category name"
            }

            return false;
        }
    }

Or, intercept the specific actions first:

routes.MapRoute(
name: "CategoryDetails", 
url: "category/create", 
defaults: new { controller = "Category", action = "Create", categoryName = UrlParameter.Optional });

routes.MapRoute(
name: "CategoryDetails", 
url: "category/delete", 
defaults: new { controller = "Category", action = "Delete", categoryName = UrlParameter.Optional });

//Do one for Edit, Delete

//CategoryDetails route after
routes.MapRoute(
name: "CategoryDetails", 
url: "category/{categoryName}", 
defaults: new { controller = "Category", action = "Details", categoryName = UrlParameter.Optional });
like image 96
Dave Bish Avatar answered Nov 11 '22 18:11

Dave Bish


While the answers above are correct, this is a simpler solution, although it will not dynamically update if you add actions to your controller as Dave's answer will.

As I understand it if {key} is an existing action you want it to be handled by the default route instead of using the Details action on the Category controller.

In order to achieve that you could list all the possible actions in the key constraint:

routes.MapRoute(
    name: "CategoryDetails",
    url: "Category/{key}",
    defaults: new { controller = "Category", action = "Details" },
    constraints: new { key = @"[^create|update|delete]" }
);

In this example the CategoryDetails route will match only if the url is not Category/create or Category/update or Category/delete. For example ads/cars will match and use the Details action.

like image 2
Daniel Hoffmann-Mitscherling Avatar answered Nov 11 '22 19:11

Daniel Hoffmann-Mitscherling