I'm seeing strange ActionLink behaviour, why is the url displayed in the browser not displaying the seemingly correct controller?
Asked Answered
L

3

6

I have the following ActionLink:

@Html.ActionLink("Upload", "Upload", "File")

yet when I hover over the link, the url displayed in the browser is http://localhost:44334/Upload. Where is the controller in this url? Strangely, clicking the url takes me to my File/Upload view, and yet stranger, the url displayed in the browser's address bar is https://localhost:44334/Upload.

The ActionLink is on page Home/Explorer, so AFAIK a controller name is normally necessary.

Why is the ActionLink helper leaving out the controller name, and why is the link still working? I have tried refreshing the page with cache clearing, with no difference. I don't know what else do besides leave it alone because it works, but I'm concerned this is some quirk and it will no longer work when I deploy my site.

My routing is still standard, out-of-box, in the Startup class's Configure method:

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

Strangely enough, I have now added a Download link each row of an HTML table of files, looking like this:

@Html.ActionLink("Download", "Download", "File", new { filePath = file.Path })

and this link also renders without the controller name, e.g:

https://localhost/Download?filePath=....
Lax answered 6/4, 2018 at 7:27 Comment(7)
Have you defined a specific route definition for it?Croton
do you have an entry in routeconfig that has "upload" in url parameter, and "file" and "upload" in controller and action respectively in other parameter?Osmosis
Without route definition in RouteConfig it's difficult to tell if the route definition or route order is wrong. It is possible that a route defined without controller name in URL but has default values to controller and action name parameter.Austin
You obviously have a route defined with url: "Upload" with defaults: new { controller = "File" ...} (or the equivalent RouteAttribute)Croton
I have changed no routing at all. It is still exactly as output my the MVC Application project template. I have now showed the routing in my question.Lax
@StephenMuecke I don't obviously have any Upload route defined, as explained in the edited question.Lax
Can you include the declaration of your action used for upload and any attributes defined on it?Cheat
P
5

Http{Verb}("{routeTemplae}") is usually used when building a REST API. In order to be able to generate URLs for the default MVC controllers when using attribute routing you will need to use Route attribute.

The original controller probably did not have a route prefix which meant that

//POST /Upload //<-- when there is no prefix on the controller
[HttpPost("Upload")]

on the controller would route to /Upload with no controller prefix.

By including a prefix for the route on the controller it will include the controller name when generating URLs when using attribute routing.

[Route("[controller]"]
public class FileController : Controller {
    //POST File/Upload
    [HttpPost]
    [Route("Upload")]
    public async Task<ActionResult> Upload(UploadFilesViewModel model, IEnumerable<IFormFile> files) {
        //...
    }

    //GET File/Download
    [HttpGet]
    [Route("Download")]
    public async Task<IActionResult> Download(string filePath) {
        //...
    }
}

Reference Routing in ASP.NET Core

Reference Routing to Controller Actions

Pipsqueak answered 11/4, 2018 at 11:23 Comment(2)
You are dead right, thanks, my friend. I don't need the Route attribute, but you are correct, as I said in my own answer below, that [HttpPost("Upload")] routes straight to /Upload. You are a winner.Lax
Just wanted to show that it could still work with attribute routing seeing as you mentioned that you were using the default convention-based routing.Pipsqueak
L
3

This is most strange, but in my FileController, I had leftover attribute routing from when I was using the the controller for a Web API instead of in the MVC web application. The methods essentially looked like this:

[HttpPost("Upload")]
public async Task<ActionResult> Upload(UploadFilesViewModel model, IEnumerable<IFormFile> files)

[HttpGet("Download")]
public async Task<IActionResult> Download(string filePath)

Now that I have removed the route names from the attributes, and have just plain [HttpPost] and [HttpGet], the actionlinks work correctly and render URLs that now do contain the controller name.

Lax answered 11/4, 2018 at 11:5 Comment(0)
R
0

[HttpPost("Upload")]

Here Using POST method so no need of prefix like '/' on MVC controller

[HttpGet("Download")] public async Task Download(string filePath)

Rockingham answered 18/4, 2018 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.