I have a problem with back linking from area view to non area view.
Current structure
Web application tree:
/Controller/BaseController.cs
/Views/Base/Index.cshtml
/Areas/Area1/Controller/SettingsController.cs
/Areas/Area1/Views/Setting/Index.cshtml
Default route config:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
name: "Localization",
url: "{culture}/{controller}/{action}/{id}",
defaults: new { culture = "de-DE", area = "", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { area = "", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Area route config:
public class Area1AreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Area1";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Photovoltaics_localized",
"{culture}/Photovoltaics/{controller}/{action}/{id}",
new { culture = "de-DE", action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Area1_default",
"Area1/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
Register route configs (Global.asax.cs)
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
[..]
Problem
When I'm inside a base view (/Views/Base/Index.cshtml) the code #Html.ActionLink("My home link", "Index", "Home") generates the link I expected http://localhost:81/de-DE/Home .
When I'm inside a area view (/Areas/Area1/Views/Setting/Index.cshtml) the same code generates a link http://localhost:81/de-DE/Area1/Home but this points to nowhere.
Tried so far
I learned that the code #Html.ActionLink("My home link", "Index", "Home", new { area = ""}, null) works in both, area and non area views and leads to the correct http://localhost:81/de-DE/Home view.
Question
How can I structur my route configs in a way that calling a link creation methode with no area as parameter always links to the base views/controllers?
Or is there a better solution to achieve this?
What I expect is:
#Html.ActionLink("My home link", *action*, "controller")
= http://localhost:81/de-DE/action
#Html.ActionLink("My home link", *action*, *controller*, new { area = *area*}, null)
= http://localhost:81/de-DE/area/action
This has nothing to do with routing. This is the default behaivor for the ActionLink method URL creation. You can see this on the following code (taken from the ASP.NET MVC codeset):
if (values != null)
{
object targetAreaRawValue;
if (values.TryGetValue("area", out targetAreaRawValue))
{
targetArea = targetAreaRawValue as string;
}
else
{
// set target area to current area
if (requestContext != null)
{
targetArea = AreaHelpers.GetAreaName(requestContext.RouteData);
}
}
}
As you can see if you don't pass a value for area, it will take the current area you are in.
The only solution I can think of, would be to create your own HTML extension. Something similar to this:
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName)
{
return htmlHelper.ActionLink(linkText, actionName, controllerName, new { area = String.Empty });
}
Related
Issue/Try 1:
I have a custom route map:
routes.MapRoute(
name: "User Profile",
url: "User/{userId}/{controller}/{action}/{id}",
defaults: new { Areas = "User", controller = "Kpi", action = "Index", id = UrlParameter.Optional }
);
If i manually navigate to the URL /User/f339e768-fe92-4322-93ca-083c3d89328c/Kpi/View/1 the page loads with a View Error: The view 'View' or its master was not found or no view engine supports the searched locations.
Issue/Try 2:
Stopped using the custom route and set up my controller as instead:
[RouteArea("User")]
[RoutePrefix("{userId}/Kpi")]
public class KpiController : BaseUserController
{
[Route("View/{id}")]
public async Task<ActionResult> View(string userId, int? id = null)
{
[...]
}
}
This now works i can navigate to the URL and the View displays fine.
Issue for both:
Although I can navigate manually to both and they load I can't seem to generate the URL correctly using ActionLink:
#Html.ActionLink(kpi.GetFormattedId(), "View", "Kpi", new { Area = "User", userId = Model.Id, id = kpi.Id }, null)
It generates: /User/Kpi/View/1?userId=f339e768-fe92-4322-93ca-083c3d89328c instead of /User/f339e768-fe92-4322-93ca-083c3d89328c/Kpi/View/1
URL Mapping
After some time i have found the solution for the custom mapping i was adding in the main RouteConfig.cs and not in the Area Registration. Moving the MapRoute to the Area works correctly and without the RouteArea, RoutePrefix and Route attributes in the Controller.
Area Registration
public class UserAreaRegistration : AreaRegistration
{
public override string AreaName => "User";
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "User",
url: "User/{userId}/{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"User_default",
"User/{controller}/{action}/{id}",
new {action = "Index", id = UrlParameter.Optional}
);
}
}
Links
Instead of using ActionLink i am now using RouteLink.
#Html.RouteLink("KPIs", "User", new { Controller = "Kpi", Action = "Index", userId = Model.Id })
The default url of the application is
http://servername/Root/ITProjects
There is a menu item with 'Team' on the default page which should redirect to another controller with index which will display a dropdownlist at the following url
http://servername/Root/ITProjects/Team
It's working fine so far.
However when the user selects an item in the dropdownlist, it should go to the url below
http://servername/Root/ITProjects/Team/Index?Id=7
But it's directing to
http://servername/Team/Index?Id=7
and throwing the 404 error. It is missing the folder path 'Root/ITProjects' after the servername. It's working fine on localhost where there is no folder path but failing on deployment to test or prod servers
[AuthorizeAD(Groups = "APP_xxxx_Users")]
public class TeamController : Controller
{
public int pageSize = 5;
private IProjectService _projectService;
public TeamController(IProjectService projectService)
{
this._projectService = projectService;
}
public ActionResult Index(int? Id, int? page)
{
int pageNumber = (page ?? 1);
var viewModel = new TeamViewModel();
if (Id != null)
{
viewModel.SelectedMember = (int)Id;
viewModel.Tasks = this._projectService.GetTasksByStaff(viewModel.SelectedMember).ToPagedList(pageNumber, pageSize);
}
return View(viewModel);
}
[HttpPost, ActionName("Index")]
public ActionResult IndexPost(int Id, int? page)
{
int pageNumber = (page ?? 1);
var viewModel = new TeamViewModel();
viewModel.SelectedMember = Id;
if (ModelState.IsValid)
{
viewModel.Tasks = this._projectService.GetTasksByStaff(viewModel.SelectedMember).ToPagedList(pageNumber, pageSize);
}
return View(viewModel);
}
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
As part of Index view when dropdownlist item is selected
#Html.DropDownListFor(m => m.SelectedMember, new SelectList(Model.StaffList, "UniqueId", "Initials", Model.SelectedMember), new { #class = "btn btn-default btn-color", onchange = #"form.action='/Team/Index?Id=' +this.value;form.submit();" })
Your MVC application is in a sub-directory of another application, so IIS considers the root of the parent application instead of the root of your MVC application.
In IIS, you need to convert the virtual directory to an Application: choose your virtual directory and "Convert to Application." If you are unable to do that, then you need to modify your routes in routes.config to take the virtual directory into account:
routes.MapRoute(
"Default", // Route name
"Root/ITProjects/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
your default route for controllers looks like this :
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You can add /Root/ITProjects/ before the URL to change the default controller path
I am trying to remove area name and controller name from URL.I am able to remove area name. But if trying to remove controller name then "Page not found error" displayed. Below is the code snippet which I have used to remove the area and controller name.
public class HomeAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Home";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
//context.MapRoute(
// "Home_default",
// "Home/{controller}/{action}/{id}",
// new { action = "Index", id = UrlParameter.Optional }
//);
//context.MapRoute(
// "Home_default",
// "{controller}/{action}/{id}",
// new { action = "Index", id = UrlParameter.Optional },
// new { controller = "(Home)" }
//);
context.MapRoute(
"Home_default",
"{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new { controller = "(Home)" }
);
}
}
In the registerarea function the first two routes(commented) are working perfectly. if I use the first one the URL comes with Area/Controller/Action. If I use second one the area is not coming in URL.The URL come ups with Controller/Action.
In the third one I am trying to remove both area and Controller
Is any thing wrong in my third route. Please suggest
Have you tried this:
routes.MapRoute("default", "{action}/{id}", new {controller = "Home", action = "Index", id = UrlParameter.Optional});
I have some controllers in root and I've registered its rout like this as default:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And I have an area named 'Admin' which its rout registered like this:
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Default_Admin",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
My problem is that user can request an action inside a controller (e.g: UserController/Index) in Admin area without specifying its area in url.
I mean these urls both are same:
http://localhost:2374/Admin/Default1/Index
http://localhost:2374/Default1/Index
And I want to avoid the second url.
Thanks
Request ["fileName"] return null?? Why?
Full image: http://i.stack.imgur.com/U1MzX.jpg
Controller:
Full image: http://i.stack.imgur.com/DCQNG.jpg
Route
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"AdminLogin",
"Admin/",
new { controller = "Account", action = "Login" }
);
//NossaIgreja/{nomePastor}
routes.MapRoute(
"Pastor", // Route name
"Pastor/{id}", // URL with parameters
new { controller = "NossaIgreja", action = "Pastor" } // Parameter defaults
);
routes.MapRoute(
"Download", // Route name
"Downloads/Boletim/{year}/{week}", // URL with parameters
new { controller = "Downloads", action = "DownloadBoletim" }, // Parameter defaults
new { year = #"\d+", week = #"\d+" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
, new string[] { "SextaIgreja.Web.Controllers" }
);
}
Area registration
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new string[] { "SextaIgreja.Web.Areas.Admin.Controllers" }
);
}
}
Your controller action should take "fileName" parameter, instead of doing a Request["fileName"]. As long as your query string parameter matches the name of the parameter in your controller mvc should pass it in automatically.
If Remover is an MVC action than I cannot see the parameter in Remover Action called fileName
It means when call Remover action the fileName in your querystring is not getting automatic model binding