0

I can't wrap my mind around the routing mechanism in asp.net core MVC 2.

Here's what I have:
I already built a functioning page to add 'Materials' to a 'Application'.

The URL to call this page is:
http://localhost:33333/AddMaterial/Index/57
which uses the default route:

routes.MapRoute(
    name: "default",
    template: "{controller=Home}/{action=Index}/{id?}"
);

Whereby 57 is the application id, so that I know what 'Application' gets the new 'Material'. The Index Method in the controller looks like this, and works like expected:

[HttpGet] public IActionResult Index(string id)
{
    var model = GetModel(context, int.Parse(id));
    return View("Index", model);
}

So far so good... Now here's my problem:
I want to use the same controller and view to also edit 'Materials'. But for that i'd need two parameters in Index(). I'd need:

string applicationId
string materialId

as parameters.

So I added a new route:

routes.MapRoute(
    name: "whatImTryingToAchieve",
    template: "{controller}/{action}/{applicationId?}/{materialId?}"
);

And of course I updated the controller:

public IActionResult Index(string applicationiId, string materialId)
{            
    // Do stuff with materialId etc.
    // ...
    return View("Index", model);
 }

I know that the routing system has a specific order. So I tried defining my new route before the default route. That didn't work. I then tried to put it after the default route, which didn't work either.

I read through a lot of information about the routing system, but I didn't seem to find the answer to my simple question:
How can I add another, specific route?

Help would be much appreciated :)

EDIT: Attribute based routing as suggested by Igors Šutovs

Controller:

[Authorize(Roles = "Admins")] 
[Route("AddMaterial")]
public class AddMaterialController : Controller
{
    //....

    [Route("AddMaterial/{applicationId}/{otherid}")] // Nope. Nothing.
    [HttpGet] public IActionResult Index(string applicationId, string otherid) 
    { 
        return View(); 
    }

    [Route("AddMaterial/Index/{applicationId}")]  // Didn't work.
    [Route("AddMaterial/{applicationId}")]        // Didn't work either...
    [HttpGet] public IActionResult Index(string applicationId) 
    { 
        return View(); 
    }
}

So much for Attribute base routing.

5
  • 1
    What error do you get? Is there a complaint that there's more than one available action or does it just not resolve the route at all? Commented Nov 15, 2017 at 10:53
  • @Kirk It doesn't resolve it at all. Commented Nov 15, 2017 at 16:03
  • Could it be because you've misspelled applicationiId in the Index action? I don't expect that's the entirety of your problem, but it's not a good start. Commented Nov 15, 2017 at 16:06
  • it actually could be, I'll give it a try tomorrow. Let me just ask you this: Was the way I approached the issue correct in principle? Commented Nov 15, 2017 at 16:11
  • @serpent5 that wasn't the problem either. Commented Nov 16, 2017 at 8:39

1 Answer 1

2

I will provide my subjective opinion on the essence of the described problem. It seems that the question could be rephrased as: "What is the correct ASP.NET Core way to design routes and resolve such situations with multiple parameters?"

TLDR: use Attribute-Based Routing

This is the new type of routing which was added in ASP.MVC 5. Since then the old routing mechanism has been regarded as "Conventional-Based". ASP.NET Core currently allows mixing of both. I will provide a detailed example of how to solve the described problem using the Attribute-Based Routing only because the new approach provides the following advantages:

  • Route information is moved closer to controller actions, hence code is easier to understand and troubleshoot
  • Controller names and their method are decoupled from route names

Moving on to the solution. Let's assume that we have 2 models: Application and Material. I would create 2 distinct controllers to manage each. From your example, I understand that the relationship between these domain entities is one-to-many e.g. one Application could have many Materials. This suggests the following routes:

GET: applications/{applicationId}
GET: applications/{applicationId}/materials/{materialId}

...with a look back at principles of Restful Routing.

The ApplicationController would then look like this:

[Route("applications")]
public class ApplicationController
{
    [HttpGet("{applicationId}")]
    public IActionResult Index(string applicationId)
    {
        // return your view
    }
}

While the MaterialController would look like this:

[Route("applications/{applicationId}/materials")]
public class MaterialController
{
    [HttpGet("{materialId}")]
    public IActionResult Index(string applicationId, string materialId)
    {
        // return your view
    }
}

The call to UseMvc(..) extension method in Configure method of Startup.cs can now be simplified to just:

app.UseMvc();

Hope you'll find it useful!

Sign up to request clarification or add additional context in comments.

1 Comment

I did find it useful and I upvoted your answer. Unfortunately it didn't work in my case. I solved the problem by just passing applicationId&materialId as one parameter and parsing it by hand. It's a hack but at least it works. And the fact that even in the official documentation didn't answer my VERY SIMPLE AND ACTUALLY VALID QUESTION shows that I'll be doing far more 'hacks' to actually make asp.net core work for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.