Skip to content
This repository has been archived by the owner. It is now read-only.

Taghelpers not resolving when accessing an action with a route attribute #4658

Closed
EricJFisher opened this issue May 17, 2016 · 9 comments

Comments

Projects
None yet
4 participants
@EricJFisher
Copy link

commented May 17, 2016

I'm seeing add results.

I have a layout page with the following navigation

<ul>
    <li><a asp-controller="Character" asp-action="Index">Characters</a></li>
    <li><a asp-controller="Equipment" asp-action="Index">Equipment</a></li>
</ul>

From most of the application this navigation works properly resolving to...

<ul>
    <li><a href="/Character">Characters</a></li>
    <li><a href="/Equipment">Equipment</a></li>
</ul>

In my CharacterController though I have a Route Attribute on one of my actions...

[HttpGet]
[Route("[controller]/{name}/Details")]
public IActionResult Details(string name) { ... }

I am able to access this action properly through the custom route I've added to it, but when I do the navigation from my layout page resolves to...

<ul>
    <li><a href="">Characters</a></li>
    <li><a href="">Equipment</a></li>
</ul>

Causing navigation to no longer work, until I type in the URL manually, it only breaks when visiting the page with this route attribute, and removing the route attribute causes the tag helpers to resolve properly again. To me this is unexpected as I would expect the tag helpers to continue to resolve despite the route used to access a view. Any thoughts?

@Eilon

This comment has been minimized.

Copy link
Member

commented May 18, 2016

The attribute route on your action has a required parameter called name, for which a value isn't supplied.

Try this instead:

<ul>
    <li><a asp-controller="Character" asp-action="Index" asp-route-name="SomeName">Characters</a></li>
    <li><a asp-controller="Equipment" asp-action="Index" asp-route-name="AnotherName">Equipment</a></li>
</ul>

Note the extra asp-route-name="SomeName" values, which add a key of name with a value of SomeName when generating the URL. This can then match the attribute route template "[controller]/{name}/Details", which has the current controller's name (e.g. Home of HomeController), then the value of name, and then the literal text Details.

@EricJFisher

This comment has been minimized.

Copy link
Author

commented May 18, 2016

I understand when utilizing the Details route name is a required parameter, but the application is also using the default route {controller=Home}/{action=Index}/{id?} as well.

I'm able to access this route using /Home or /Home/Index as well as from the navigation on my layout page without any problems from every page except the results of my Details action.

I am able to access the Details action through the route specified in it's Route Attribute without issue using <a asp-action="Details" asp-controller="Character" asp-route-name="@item.Name">@item.Name</a> as well.

It's only when I'm looking at the results of my Details action that all the tag helpers go fubar... It's like by using the custom route when in the scope of the action using that route you can't use tag helpers that utilize any other route. So saying I were to set up an application that needed a variety of routes for SEO reasons... [controller]/{name}/Details, [controller]/{campaign}/Characters, and [controller]/{guild}/Roster

then for my layout page would I need...

<ul>
    <li><a asp-controller="Character" asp-action="Index" asp-route-name="CharacterName" asp-route-campaign="CampaignName" asp-route-guild="GuildName">Characters</a></li>
    <li><a asp-controller="Equipment" asp-action="Index" asp-route-name="EquipmentName" asp-route-campaign="CampaignName" asp-route-guild="GuildName">Equipment</a></li>
</ul>

Even though Character/Index and Equipment/Index are still valid routes on their own? (I can just drop them in the URL and they work fine, and tag helpers go back to working properly until I access the Details Action again)

Keep in mind, I'm not trying to fix this single instance, I either am not seeing the "why" it works this way, or this is working erroneously.

As I see it, this means my layout would need to take into consideration any and every action that accesses it to handle any and all possible custom routes (even when those routes don't conflict) meaning I'd need to update my layout with unused tags anytime I add a new custom route... That is concerning if it is the case...

@Bartmax

This comment has been minimized.

Copy link

commented May 18, 2016

When you are looking at the Details page on the url localhost/Character/someName/Details, the name property is populated so, I think Mvc tries to match a route in <a asp-controller="Character" asp-action="Index"></a> to:

Controller = "Character"
Name = "someName"
Action = "Index"

and somehow it get it's priority for the value name even if it doesn't found a match?

When I first read about this it looked like expected behavior from mvc, but giving it one more careful read I think there's something that's is not working as it should.

/cc @Eilon

@miguellira

This comment has been minimized.

Copy link

commented May 18, 2016

@EricJFisher Do you have a repo? I just mocked up something based on your post and it looks good to me:
pasted_image_5_18_16__3_42_pm

@Eilon

This comment has been minimized.

Copy link
Member

commented May 19, 2016

If you can upload a sample project that has the appropriate project.json, Startup.cs, controllers, and Views, we can take a close look and see what's going on here.

@EricJFisher

This comment has been minimized.

Copy link
Author

commented May 19, 2016

I have a private repo I've given you both access to at https://github.com/EricJFisher/ForgingAheadWithDotNetMvcCourse it's a copy so if you need to tinker, see something wrong, etc please feel free to point it out. I don't think I've got anything wrong, but that isn't to say there isn't anything wrong. (The app is in "sample app" folder, this app is for teaching purposes some things aren't exactly "best practice" as I'd be still teaching them things required to be able to do things in a better way)

@Eilon

This comment has been minimized.

Copy link
Member

commented May 19, 2016

@EricJFisher thanks for sharing the codes! One thing that immediately caught my eye is that Startup.cs has 2 calls to UseMvc():

app.UseMvc(); 

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

The first call will end up handling all the attribute routing requests (because calling UseMvc() automatically handles all attribute routes). But of course it won't handle the "conventional route" templates. Then the second to UseMvc() will handle both attribute routes and conventional routes. However, it will never actually handle calls to attribute routes because the first instance of MVC would have already handled it! This also affects generating URLs because a given request to an instance of MVC can only generate URLs that are available within that instance of MVC.

So:

app.UseMvc(); // handles only attribute-route requests, will generate URLs only
                // *to* other attribute-route enabled actions

app.UseMvc(routes => 
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
}); // handles attribute routes (but will never actually see them because the first call already handled them)
// also handles all conventional routes.

I suspect that if you delete the first call to UseMvc() that everything might work.

Can you let me know?

@EricJFisher

This comment has been minimized.

Copy link
Author

commented May 19, 2016

@Eilon That was it, it appears to be working fine now that I've removed the first app.UseMvc(); (both the route attributes and default. Thank you, sorry for taking up your time with this. So this was error on my end, not an issue with the actual framework :)

@Eilon

This comment has been minimized.

Copy link
Member

commented May 19, 2016

No problem at all, thanks! Was definitely a fun one to investigate 😄

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.