MVC Route conflicting with existing Folder causes 404 - asp.net

I did see answers for similar issues, but none of them works for this situation.
I have MVC4 application with registered area called "Settings", with one "Manage"-controller. I also have folder in my web project with sources called "Settings", so the folder Structure is the following:
+ WebProjectFolder
+ Areas
+Settings
+Controllers
ManageController.cs
+ SettingsAreaRegistration.cs
...
+ Settings
+ SomeClasses.cs
ManageController is very simple:
public class ManageController : Controller
{
public ActionResult Index()
{
return Content("WORKS FINE!");
}
}
Area registration is also very simple:
public class SettingsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Settings";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.IgnoreRoute("Settings/{*pathinfo}");
context.Routes.RouteExistingFiles = false;
context.MapRoute(
"Settings_default",
"Settings/{controller}/{action}/{id}",
new {area = context.AreaName, controller="Manage", action = "Index", id = UrlParameter.Optional }
);
}
}
The problem:
http://mysite/settings - 404
http://mysite/settings/Manage - 404
http://mysite/settings/Manage/Index - 404
In case I remove line "context.Routes.IgnoreRoute("Settings/{*pathinfo}");"
Results are the following:
http://mysite/settings - 404
http://mysite/settings/Manage - WORKS FINE!
http://mysite/settings/Manage/Index - WORKS FINE!
Only If I remove/rename existing folder "Settings", then results are correct.
Similar situation with having controller named the same as folder.
How to make MVC ignore existing folder and always give priority to the Controller?

I think you wanted to set RouteExistingFiles to true.
context.Routes.RouteExistingFiles = true;
Excerpt:
true if ASP.NET routing handles all requests, even those that match an existing file; otherwise, false. The default value is false.

Related

MVC 6 Areas and multiple login pages redirect

I'd been searching for a solution to this problem for quite a long time but unfortunately haven't found any nice and elegant way to handle it.
Here are the details:
My MVC 6 application use Areas. Each area has separate directories for the Controllers, Views etc.
Authentication is based on the standard out of the box web application template with user accounts stored in sql server
What I want to achieve is:
When user enters /AreaA/Restricted/Page then he is redirected into /AreaA/Account/Login
When user enters /AreaB/Restricted/Page then he is redirected into /AreaB/Account/Login etc...
Even though I can change the stanard login page redirect from "/Account/Login" into something different like this:
services.Configure<IdentityOptions>(options=> {
options.Cookies.ApplicationCookie.LoginPath =
new Microsoft.AspNet.Http.PathString("/HardcodedAreaName/Account/Login");
});
I am not able to redirect into different actions/login pages for each area.
Prior to MVC 6 I was able to use AuthorizeAttribute with url parameter:
public class CustomAuthorization : AuthorizeAttribute
{
public string Url { get; set; }
// redirect to login page with the original url as parameter.
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult(Url + "?returnUrl=" + filterContext.HttpContext.Request.Url.PathAndQuery);
}
}
and then passing the area dependent url by decorating each controller:
[CustomAuthorization(Url = "/Admin/Account/Login"]
public class AdminAreaController : Controller
{ ...
But it does not work anymore :(
Try the following and see if it works (I did try this and it works fine, but not sure If I have covered all scenarios):
The place where you register you CookieAuthentication middleware, you can do something like
app.UseCookieAuthentication(o =>
{
o.LoginPath = "/area1/login1";
o.AuthenticationScheme = "scheme1";
//TODO: set other interesting properties if you want to
});
app.UseCookieAuthentication(o =>
{
o.LoginPath = "/area2/login2";
o.AuthenticationScheme = "scheme2";
//TODO: set other interesting properties if you want to
});
On you controller/action, specify the authentication scheme..example:
[Authorize(ActiveAuthenticationSchemes = "scheme1")]
public IActionResult Test1()
{
return Content("Test1");
}
[Authorize(ActiveAuthenticationSchemes = "scheme2")]
public IActionResult Test2()
{
return Content("Test2");
}

.NET MVC 5 Only one area not working under IIS

I have problem with one area in my project called 'Reports'. I always get 404 error when I try to access some controller from this Area. This problem only occurs when I run my application on local IIS (Windows 8.1). On other machine (windows 7 and local IIS) everything is ok. Even on this windows 8.1 machine, but IIS Express everything is working well.
I was trying to clear temp files, but no resuls.
Areas are registed such like this:
public class ReportsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Reports";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Reports_default",
"Reports/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
And in Global.asax, Application_start() method:
AreaRegistration.RegisterAllAreas();
I dont know where could be the problem. Do you have any ideas?
Check event viewer. I had this problem and the 'Reports' URL was a virtual directory having to do with SQL Server Reporting Services.
Try this:
public class ReportsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Reports";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Reports_main",
"Reports/{controller}/{action}/{id}",
new { area = "Reports", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Reports_default",
"Reports/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
The Reports_default routing rule sets Index to be the default action for a given controller.
You need to add another Reports_main rule that will set a default controller when you access the root of the area e.g. /Reports. In this rule I assume that the default controller is Home but you can change that to fit your project.
The default AreaRegistration scaffold by Visual Studio does not include a default for controller, meaning that providing a controller in the URL is required.
/Reports/Home // This works (if you have a home controller)
/Reports // This doesn't work
To make the controller optional, you need to provide a default.
public class ReportsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Reports";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Reports_default",
"Reports/{controller}/{action}/{id}",
// Note that controller is defaulted to Home
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Note also that the order in which routes are registered is the same that they will be executed for the entire application. Typically, this means that you must call AreaRegistration.RegisterAllAreas() before you call RouteConfig.RegisterRoutes(RouteTable.Routes).
The answer provided by Tasos will also work, but is incorrectly configured:
Specifying a default area within an AreaRegistration is redundant and unnecessary.
Reports_default in his example is an unreachable execution path, which makes it also redundant and unnecessary.

asp.net mvc 3 areas and url routing configuration

I have problem with create ulr routing for asp.net mvc3 application.
My project has this structure :
Areas
EmployeeReport
Controllers
Report
Views
Report
List
....
Controllers
Login
Viwes
Login
...
EmployeeReportAreaRegistration.cs :
public class EmployeeReportAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "EmployeeReport";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
var routes = context.Routes;
routes.MapRoute(null, "vykazy/vykazy-zamestnance", new { Area = "EmployeeReport", controller = "Report", action = "List" });
}
}
Global.asax :
routes.MapRoute(null, "prihlasit", new { controller = "Login", action = "Login" });
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Default", action = "Welcome", id = UrlParameter.Optional });
When i try load "http://localhost/app_name/vykazy/vykazy-zamestnance
i get this exception :
The view 'List' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Report/List.aspx
~/Views/Report/List.ascx
~/Views/Shared/List.aspx
~/Views/Shared/List.ascx
~/Views/Report/List.cshtml
~/Views/Report/List.vbhtml
~/Views/Shared/List.cshtml
~/Views/Shared/List.vbhtml
Well, where I do mistake ?
Thanks
revised answer:
Adding to Context.Routes directly means it loses any information about Areas.
Either use AreaRegistration.MapRoute (which is overriden to put in the Area information).
context.MapRoute(...);
Or put the area in the DataTokens parameter (not the defaults parameter as you have done here)
context.Routes.MapRoute("", "url", new {...}, null, new {area = this.AreaName});
Your folder structure for your area should look like so:
Areas
EmployeeReport
Controllers
Views

Infinite URL Parameters for ASP.NET MVC Route

I need an implementation where I can get infinite parameters on my ASP.NET Controller. It will be better if I give you an example :
Let's assume that I will have following urls :
example.com/tag/poo/bar/poobar
example.com/tag/poo/bar/poobar/poo2/poo4
example.com/tag/poo/bar/poobar/poo89
As you can see, it will get infinite number of tags after example.com/tag/ and slash will be a delimiter here.
On the controller I would like to do this :
foreach(string item in paramaters) {
//this is one of the url paramaters
string poo = item;
}
Is there any known way to achieve this? How can I get reach the values from controller? With Dictionary<string, string> or List<string>?
NOTE :
The question is not well explained IMO but I tried my best to fit it.
in. Feel free to tweak it
Like this:
routes.MapRoute("Name", "tag/{*tags}", new { controller = ..., action = ... });
ActionResult MyAction(string tags) {
foreach(string tag in tags.Split("/")) {
...
}
}
The catch all will give you the raw string. If you want a more elegant way to handle the data, you could always use a custom route handler.
public class AllPathRouteHandler : MvcRouteHandler
{
private readonly string key;
public AllPathRouteHandler(string key)
{
this.key = key;
}
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var allPaths = requestContext.RouteData.Values[key] as string;
if (!string.IsNullOrEmpty(allPaths))
{
requestContext.RouteData.Values[key] = allPaths.Split('/');
}
return base.GetHttpHandler(requestContext);
}
}
Register the route handler.
routes.Add(new Route("tag/{*tags}",
new RouteValueDictionary(
new
{
controller = "Tag",
action = "Index",
}),
new AllPathRouteHandler("tags")));
Get the tags as a array in the controller.
public ActionResult Index(string[] tags)
{
// do something with tags
return View();
}
That's called catch-all:
tag/{*tags}
Just in case anyone is coming to this with MVC in .NET 4.0, you need to be careful where you define your routes. I was happily going to global.asax and adding routes as suggested in these answers (and in other tutorials) and getting nowhere. My routes all just defaulted to {controller}/{action}/{id}. Adding further segments to the URL gave me a 404 error. Then I discovered the RouteConfig.cs file in the App_Start folder. It turns out this file is called by global.asax in the Application_Start() method. So, in .NET 4.0, make sure you add your custom routes there. This article covers it beautifully.
in asp .net core you can use * in routing
for example
[HTTPGet({*id})]
this code can multi parameter or when using send string with slash use them to get all parameters

ASP.NET MVC route returning 404 without action

I am working on a very simple application, using MVC2 Preview 1.
I have a controller named ContentController. My problem is that /Content/Index works correctly, but /Content/ returns a 404. I am running the application on the Studio Development Server.
Tested with RouteDebugger but /Content/ returns a 404, and does not display any debugging information.
I have not changed the routing code:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
This is my controller:
public class ContentController : Controller
{
IRepository _repo = new SimpleRepository("db", SimpleRepositoryOptions.RunMigrations);
public ActionResult Index()
{
var content = _repo.GetPaged<Content>(0, 20);
return View(content);
}
It's a shot in the dark, but do you have a directory named /Content/ as well?
/Content is a controller, which is basically just a collection of actions. ASP.NET MVC needs to know WHICH action you want to run, so by leaving out the action asp.net mvc doesn't know what action to return and gives a 404.
You can tell it a default either by adding a route:
eg:
routes.MapRoute("ContentDefault", "Content", new {controller = "Content", action = "Index"});
The attributes are defined as follows:
'ContentDefault`: Name of the Route (must be unique in your routing table)
Content: The URL segment (try changing this to 'Content/Much/Longer/URL' and then go to http://localhost/Content/Much/Longer/URL to see how this works)
new {controller=.., action=...}: which controller/action combo to run for this route.
You could also override HandleUnknownAction in your controller:
protected override void HandleUnknownAction(string actionName)
{
return RedirectToAction("index");
}
Oh and incidentally, an extra piece of advice about routing.... if you add something to the route in braces { } these will be passed to the action as an attribute.
e.g. /Content/Much/Longer/Url/{page}
so the URL http://localhost/Content/Much/Longer/Url/999
will pass the 999 into your action, as the page attribute
public ActionResult Index(int Page) { }
I love MVC - never going back to WebForms - this is how web development should be!

Resources