Why is this ActionLink to another area not working? - asp.net

I am testing how to build an action link to a page in another area, and every source I find says to use
Html.ActionLink("[Link Text]", "[action name]", "[controller]", new { area = "[areaName]" }, null)
except for one source I found which suggested
Html.ActionLink("[Link Text]", "[action name]",new { area = "[areaName]", controller = "[controllerName]" })
The problem is, neither of these work for me. In my MVC application I have an area called "Uploader", which contains its own Home controller, and Index page. So, in the main Index page of my MVC project, I create an ActionLink that looks like this:
#Html.ActionLink("Area Test", "Index", "Home", new { area = "Uploader" }, null)
If the link works correctly, I'll get taken to a page that reads "this is the uploader", the text on my area Index page, but instead, the main home/index page of my application just reloads.
The address I see in my browser after this reload is "https://localhost:44352/?area=Uploader".
The HomeController for the area is correctly formatted with an "Area" tag, like so:
namespace TestProject.Areas.Uploader.Controllers
{
[Area("Uploader")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
I'm using .Net 5. What am I doing wrong?

Finally found the answer here. It turns out I had my area configuration backwards: the "default" route should come last.
It should be:
endpoints.MapControllerRoute(
name: "areas",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
...instead of the other way around.

Related

Redirecting a controller and action method to its URL

I have a project that I am working on that was done in ASP.NET MVC 5.
They used the default URL structure that comes standard with the framework. For example, the AGM page was constructed like this:
Controller: Home
Action method: AGM
Without any routing setup, to access this page, you would need to go to the following URL:
www.example.com/Home/AGM
This is the URL that they sent to the press. This URL looks horrible and I want to implement a cleaner URL structure which will look like this:
www.example.com/agm
I have set it up like this in the RouteConfig.cs file:
routes.MapRoute(
name: "AGM",
url: "agm",
defaults: new { controller = "Home", action = "AGM" }
);
What I want to achieve is if the user types in www.example.com/Home/AGM then it needs to display the URL like www.example.com/agm. Instead, it displays like www.example.com/Home/AGM.
I'm not sure how to implement this?
Configure routing and define action in the url
routes.MapRoute(
name: "AGM",
url: "{action}",
defaults: new { controller = "Home", action = "AGM" }
);
Then in the AGM method redirect to www.example.com/agm
if (Request.Path.ToLower() == "/home/agm")
{
return Redirect("/agm");
}
You can simply add [Route("AGM")] and [Route("Home/AGM")] top of your Action method:
[Route("AGM")]
[Route("Home/AGM")]
public IActionResult AGM()
{
return View();
}

Page can’t be found error inside Areas controller Index

I created this Area for the admin page (Areas/System) and an AdminController inside.
But when I tried to put the URL in the address as https://localhost:44361/System/Admin it didn't break inside the Index() function. And an error page shows "This localhost page can’t be found" even there's the Index.cshtml
On side note, this works well inside HomeController > Index() when you visit https://localhost:44361.
Below is the sample code for Areas/System AdminController.
[Area("System")]
[Route("System/[controller]/[action]")]
public class AdminController : BaseController
{
public IActionResult Index()
{
return View();
}
}
Sadly you haven't posted your Startup.Configure, more specifically app.UseMvc, but considering the fact that your HomeController/Index gets fired I think the issue might be there. Defining [Area("System")] should be enough, rest is implicit.
app.UseMvc(routes =>
{
//Order is important, most specific to least specific
routes.MapRoute(
name: "MyArea",
template: **"{area:exists}/**{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Bit more reading on areas and route configuration: https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/areas?view=aspnetcore-3.0#add-area-route
I guess I got the answer. I simply removed the Route attribute and it works.
[Route("System/[controller]/[action]")]

MVC3 Routing Working 1 Direction Only

I am working on an ASP.NET mvc 3 site that contains several project entities, and then each project has several associated subpages, each that works with a component of the project.
So for instance, I could have a project with several photos, milestones, user info, etc. I have a Project Index view, as well as a Project Home which links to several component pages. Most of the components have two views, Index, and Edit/View.
So I set up a route for the edits and views. Note that my route is in an AREA called ProjectManagement
context.MapRoute(
"ProjectManagement_ProjectPageSingle",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
and my controller actions all look similar to this:
public ActionResult Edit(string projectNumber, string projectChildId)
This works well and good when I type in the URL directly in the browser. For instance:
~/ProjectManagement/Milestone/Edit/39999P110175/1
however, when I generate an action link using:
<a href="#Url.Action("Edit", new { projectNumber = Model.Project.ProjectNumber, projectChildId = entry.Id})">
the action URL ends up looking like this:
~/ProjectManagement/Milestone/Edit/39999P110175?projectChildId=1
So the route sorta works...but the action link generator doesn't? Not sure where to go from here. Any advice would be much appreciated.
Note that the same thing occurs while using #Html.ActionLink instead of #Url.Action.
Thanks!
You don't seem to have specified the area name:
#Url.Action(
"Edit",
new {
projectNumber = Model.Project.ProjectNumber,
projectChildId = entry.Id,
area = "ProjectManagement"
}
)
Also make sure that there aren't any other routes that might conflict with this one in your area registration which should look like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"ProjectManagement_default",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
}
Thanks to Michael for the response. Here's the answer for others.
I had:
context.MapRoute(
"ProjectManagement_ProjectPage",
"ProjectManagement/{controller}/{action}/{projectNumber}",
new { controller = "Project", action = "Home"}
);
///more routes
context.MapRoute(
"ProjectManagement_ProjectPageSingle",
"ProjectManagement/{controller}/{action}/{projectNumber}/{projectChildId}",
new { controller = "Project", action = "Home" }
);
The URL matched the ProjectPage route as well, so it took that one first. Had to flip the order, so the more specific route came first.
Thanks.

Returning to Calling Page Within an Area Using UrlReferrer

I have created a new MVC2 project using the ASP.NET MVC2 Web Application, which gives me the default web site. I have added a simple area in which I had a Home Controller and an Index view. That cuased the first problem with the compiler giving "Multiple types were found that match the Controller name 'Home'". I changed Home to Main and it compiled.
I added a new tab to reference the Index view in my area, opened the website and started clicking the tabs. When I visited the Area index page, I couldn't go back to the Home or About page without changing the menu, as follows:
<ul id="menu">
<li><%= Html.ActionLink("SampleArea.Main", "Index", "Main", new { area = "SampleArea" }, null)%></li>
<li><%= Html.ActionLink("Home", "Index", "Home", new { area = "" }, null)%></li>
<li><%= Html.ActionLink("About", "About", "Home", new { area = "" }, null)%></li>
</ul>
I could then cycle through the tabs correctly. I then changed the code in the LogOff view in the Account controller, as follows:
public ActionResult LogOff()
{
FormsService.SignOut();
//return RedirectToAction("Index", "Home");
return RedirectToAction(Request.UrlReferrer.AbsolutePath.ToString());
}
I am using UrlReferrer.AbsolutePath to return to the calling page if the User logs off. If the calling page happens to be the View in SampleArea, .AbsolutePath contains "/SampleArea". This is because the controller and view are the defaults, and so they are not included. As it continues, I get the following error message:
The resource cannot be found.
Description: HTTP 404. The resource
you are looking for (or one of its
dependencies) could have been removed,
had its name changed, or is
temporarily unavailable. Please
review the following URL and make sure
that it is spelled correctly.
Requested URL: /Account/SampleArea
My understanding is that /Account has been added because that is the controller it was in when LogOff was executed. It thinks /SampleArea is an action and therefore added the current controller to complete the route.
Using UrlReferrer.AbsolutePath, is there any way I can specify SampleArea as an area, or is there something else I can do to return to the correct page?
New Addition
This is even stranger than I thought. I opened the website I am currently developing and changed the return statement in view LogOut to return using AbsolutePath. A breakpoint reveals it contains "/Club/PrivacyPolicy". However, I get the same error message with the following difference:
Requested URL: /Login/Club/PrivacyPolicy
Why on earth should it prefix it with /Login which is a View, rather than /Account which is a Controller? In fact, why should it prefix it with anything at all? /Club/PrivacyPolicy
is a valid route in Global.asax.cs.
I have finally figured out how to return to the page you were on when you triggered the LogOn or LogOut request. I have used the following piece of code.
Html.ActionLink("Member LogOn", "LogOn", "Account", new { area = "", returnUrl = HttpContext.Current.Request.RawUrl }, null)
This generates
<a href='/LogIn/LogOn?returnUrl=%2FContactUs'>Member LogOn</a>
for example.
In my HttpPost ActionResult LogOn, I then have
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
Sometimes I find I just need HttpContext.Request.RawUrl.
I'm not quite sure why it has generated /LogIn/LogOn instead of /Account/LogOn, but it works as expected.

ASP.NET MVC 2 Areas 404

Has anyone been able to get the Areas in ASP.NET MVC 2 to work?
I created a new Area called "Secure" and placed a new controller in it named HomeController. I then Created a new Home/Index.aspx view. However, when I browse to http://localhost/myapp/Secure/ it gives a 404 resource cannot be found. http://localhost/myapp/Secure/Home gives the same error.
My area registration looks like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Secure_default",
"Secure/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
I also tried this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Secure_default",
"Secure/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Thanks,
Justin
I am pretty sure it was because your area registration class was in a different namespace that the project it was hosted in. It would explain why your solution worked - you registered it with the overload that takes in the namespace. I had a similar issue and it was fixed by correcting the namespace.
Sure, i've got Areas working with ASP.NET MVC 2.
Its hard for people to debug routes over SO, the easiest way is for you to use Phil Haacks Route Debugger. It'll tell you what routes (and areas) are being resolved for a particular URL. Extremely handy.
However ill take a stab, try changing your route to this:
context.MapRoute(
"Secure_default",
"Secure",
new { action = "Index", controller = "Home", id = UrlParameter.Optional }
);
The url (<yourhost>/Secure) will find your area Secure but not know which controller you hand the request to, as you have not specified a default value for controller in your areas route.
Here's my setup:
Areas
Albums
Controllers
AlbumsController.cs (namespace Web.Areas.Albums.Controllers)
Models
Views
Albums
Index.aspxx
AlbumsAreaRegistration.cs
context.MapRoute(
"Albums_Default",
"Albums",
new { controller = "Albums", action = "Index", id = UrlParameter.Optional)
The URL: http://localhost/Albums triggers the "Index" action of my "AlbumsController" in my "Albums" area.
What does you structure look like?
I got it working, the answer was to change the area registration class to this:
context.MapRoute(
"Secure_Default", // Route name
"Secure/{controller}/{action}/{id}", // URL with parameters
new { area="Secure", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new[] { typeof(Controllers.HomeController).Namespace }
);
I have no idea why it worked for another developer and not for me, also I feel like it should "just work" out of the box when you create a new Area, you shouldn't have to fiddle with the route mapping.
Anyway, thanks all for the help and I'm giving the answer to RPM for all his hard work.
Are you calling AreaRegistration.RegisterAllAreas() in your global.asax?
Sub Application_Start()
AreaRegistration.RegisterAllAreas()
RegisterRoutes(RouteTable.Routes)
End Sub
Have you tried using http://localhost/myapp/Secure/Home/index ? I find so many times that when I use index as the view name and don't specify it in the path it never works. It should work but it never works for me.
I don't like calling my views index anyways so not a big deal for me.

Resources