I am running ASP.Net MVC 5 in .NET Framework 4.8. I keep getting 404 error due to inconsistently generated URLs. For example, in my _PageNav.chstml partial that is included at the top of each page I the following to take the user back to the home page: @Url.Action("Index", new { controller = "Home" })
. In the navigation bar this resolves to <a class="navbar-brand" href="/" />
and functions properly.
When I use the same @Url.Action("Index", new { controller = "Home" })
on the same page, but later in on a button, it resolves to this: <a id="doneButton" class="btn btn-secondary px-4" href="https://localhost:44337/smrt/">Done</a>
Because of this inconsistency I often have issues where AJAX JavaScript references to the controllers end up with missing controller references such as /create
resulting in https://localhost:44337/create
instead of https://localhost:44337/home/create
or /home/create
resulting in https://localhost:44337/home/home/create
instead of https://localhost:44337/home/create
I do have also have some limitations because of security restrictions; for example I cannot have any JavaScript on the page itself so I can't write razor code in my .cshtml files that will result in JavaScript. I can only use JavaScript referenced in source files for the page.
It took a few different ideas, but I was able to solve my problem. I now get consistent URLs in just they way I need them, every time.
First, I used this article How to Build Absolute Action URLs Using the UrlHelper Class, to create the follwoing class with an extension method based on the UrlHelper Class .
using System.Web.Mvc;
namespace MVCPages.Utilities
{
public static class UrlHelperExtenions
{
/// <summary>
/// Generates a fully qualified URL to an action method by using
/// the specified action name, controller name and route values.
/// </summary>
/// <param name="url">The URL helper.</param>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
/// <param name="routeValues">The route values.</param>
/// <returns>The absolute URL.</returns>
public static string AbsoluteAction(
this UrlHelper url,
string actionName,
string controllerName,
object routeValues = null
)
{
var httpContext = url.RequestContext.HttpContext;
string scheme = httpContext.Request.Url.Scheme;
return url.Action(
actionName,
controllerName,
routeValues,
scheme
);
}
}
}
This new method dynamically gives me the root of the website no matter where the site is deployed.
I then call the new method extension in the views where I need URL consistency and pass the absolute root URL to the view using the ViewBag.
public ActionResult Index()
{
string rootUrl = Url.AbsoluteAction("Index", "Smrt");
ViewBag.RootUrl = rootUrl;
}
Since I am not allowed to use Razor to create JavaScript, I next use Razor to create a hidden HTML div tag that includes the root URL, <div id="rootUrl">https://rooturl.com/</div>
Now, in JavaScript, I use the DOM to retrieve the URL from the HTML tag; then use ad that to my ajax calls to create a complete URL for the AJAX calls.
window.onload = function () {
var rootUrl = document.getElementById("rootUrl").innerHTML;
var ajaxUrl = rootUrl + ajaxCall;
};