Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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=....
like image 524
ProfK Avatar asked Apr 06 '18 07:04

ProfK


People also ask

What is the difference between using URL action and HTML ActionLink in a view?

Yes, there is a difference. Html. ActionLink generates an <a href=".."></a> tag whereas Url. Action returns only an url.

How does Html ActionLink work?

Html. ActionLink creates a hyperlink on a view page and the user clicks it to navigate to a new URL. It does not link to a view directly, rather it links to a controller's action.


2 Answers

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

like image 129
Nkosi Avatar answered Oct 11 '22 11:10

Nkosi


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.

like image 3
ProfK Avatar answered Oct 11 '22 10:10

ProfK