Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC model nesting routes

Consider an ASP.NET MVC application with two models: let's say Company and Person. Each company has a list of persons. Each person belongs to one company only.

If you set up the model and use Visual Studio to generate the controllers/views, you get the ability to edit the companies at /Company/{id} etc. and the ability to edit the persons at /Person/{id} etc.

But I want it to be such that you can only add a person inside a company, i.e. you would edit the persons at /Company/{id}/Persons/{id}.

How can I set up this sort of routing in ASP.NET MVC 5?


EDIT:

So I did this in my routes:

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        
routes.MapRoute(
    name: "CompanyPerson",
    url: "Company/{CompanyId}/Person/{PersonId}/{action}",
    defaults: new { controller = "Person", action = "Index", PersonId = UrlParameter.Optional }
);

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

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

but it still isn't working. If I go to /Company/7/Person I get an index of persons, but /Company/7/Person/Create just gives the same index, and the "Create New" link points to /Person/Create instead of /Company/7/Person/Create

Is there just a way to set up all the routes explicitly, like Node or most other MVC frameworks?

like image 539
ian93 Avatar asked Jul 05 '14 17:07

ian93


People also ask

Can we have multiple routes in MVC?

Multiple Routes You need to provide at least two parameters in MapRoute, route name, and URL pattern. The Defaults parameter is optional. You can register multiple custom routes with different names.

How many routes can be defined in MVC?

Every ASP.NET MVC application must configure (register) at least one route in the RouteConfig class and by default, the ASP.NET MVC Framework provides one default route. But you can configure as many routes as you want.

What are the 3 segments of the default route?

The Default route maps the first segment of a URL to a controller name, the second segment of a URL to a controller action, and the third segment to a parameter named id.

What are the three segments for routing important in MVC?

The three segments of a default route contain the Controller, Action and Id.


1 Answers

Well, it doesn't work the way you're thinking. The reason is that you have two different controllers, Company and Person. You can't call both of them at the same time.

You are going to have to decide whether you want to edit a person at the Person controller, or edit them at the Company controller. Personally, I'd edit the person at the person level, but that will mean your Person.Edit method will have to take the companyId as well as the personId.

So you would then create a route like this:

routes.MapRoute(
    "CompanyPerson",                                // Route name
    "Company/{companyId}/Person/{personId}",        // URL with parameters
    new { controller = "Person", action = "Edit" }  // Parameter defaults
);

Then your Person.Edit method would look like this:

public ActionResult Edit(int companyId, int personId) {}

EDIT:

You are going to have to use constraints to do what you want.

routes.MapRoute(
    name: "CompanyPerson",
    url: "Company/{companyId}/Person/{personId}/{action}",
    defaults: new { controller = "Person", action = "Index", PersonId = UrlParameter.Optional },
    new {personId = @"\d+" }
);

However, this now means you can do /Company/7/Person/15/Create, and that just won't make any sense. The personId will simply get ignored.

As for why your Create Link isn't working, is because of the id being before the action. You'll also need another route.

routes.MapRoute(
    name: "CompanyPerson",
    url: "Company/{companyId}/Person/Create",
    defaults: new { controller = "Person", action = "Create" }
);

and this

@Html.ActionLink("Create", "Person", new { companyId = Model.companyId })

It would be a lot easier if you just stuck to the Id after the action. You also need to be careful of capitalizing variable names, as these are C# variables and are case sensitive.

like image 176
Erik Funkenbusch Avatar answered Sep 18 '22 01:09

Erik Funkenbusch