Parameter only route always being triggered MVC3 - c#

I have two very simple routes
routes.MapRoute(
"post", // Route name
postPage + "/{slug}", // URL with parameters
new { controller = "Home", action = "Article" } // Parameter defaults
);
routes.MapRoute(
"page", // Route name
"{slug}", // URL with parameters
new { controller = "Home", action = "Page", slug = homePage} // Parameter defaults
);
And here is my controller logic
public ActionResult Article(string slug)
{
return View(repo.GetPost(slug));
}
public ActionResult Page(string slug)
{
if (slug.ToLower() == MetaData.PostsPage.ToLower())
return View("listPosts", repo.GetAllPosts());
else
return View("page", repo.GetPage(slug));
}
homePage and postPage are set from value's in the database. Allowing the user to define the default page as well as the page to show posts.
My issue occurs when adding an area named "Admin". I get a controller added to my RouteTable
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Now when a user Access Admin/Account/Logon the page loads fine, but my debugger still tries to go into the Home controller and the Page action. But the RouteDebugger says it doesn't match the current request. I'm puzzled on how to fix this.
RouteDebugger screenshot: http://i.stack.imgur.com/7cpHm.png
Debugger going into my HomeControler Page AtionResult: http://i.stack.imgur.com/uSJBK.png

Actually the problem is, Area routes are overriding the global routes, to distinguish both the routes set the relevant namespace of area's controller in the context.MapRoute method in adminAreaRegistraton.cs file. i.e.
context.MapRoute(
"admin_default",
"admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
null,
new string[] { "MVCApplication1.Areas.admin.Controllers" }
);

I found out the issue.
I had a favicon.ico set in the main area of my site, but not the Admin area.
So when I went to the Admin area the browser made a request for favicon.ico that got picked up by that route. Thats why my routes looked fine in the RouteDebugger, because they were.
Thanks for the help Kundan!

Related

Tenant area route with default route

So I have a site that has basically an 'area' per tenant. so it will show up as www.site.com/ and that will go to that groups page using an area.
Thing is I also have a default route for outside the area so you can go to www.site.com/ which will take you to the actual ~/Views/Home/Index page. However if you try to type www.site.com/Home/Index or say the page to create a new group www.site.com/Group/Create it thinks it needs to go to the area which that doesn't exist and gives the 404 resource cannot be found.
Here is the default route in the RouteConfig.cs
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "TicketSystem.Controllers" }
);
Here is the route config for the area:
context.MapRoute(
"Group_default",
"{group}/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "TicketSystem.Areas.Group.Controllers" });
so the {group} is whatever group you are currently visiting and then it goes to the regular controller/action for that group. However for the default route it still seems to go to the area route instead no matter what.
I was thinking that there could be a fallback. So when it tries to go to the area and it can't find the correct controller/action it will check the default route next. If it still can't find anything it will give the 404 error resource cannot be found. Though I am not exactly sure how to do this.
So to make www.site.com/ to work and allow www.site.com/Home/Index to work.
The problem is, When you try to access /Home/Index The route engine does not know by "Home" , you meant the controller name or a groupName!
To solve this, you can create a custom route constraint which checks whether the group value in the request url is a valid controller name in your app. If yes, The request won't be handled by the area route registration definition.
public class GroupNameConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName,
RouteValueDictionary values, RouteDirection routeDirection)
{
var asm = Assembly.GetExecutingAssembly();
//Get all the controller names
var controllerTypes = (from t in asm.GetExportedTypes()
where typeof(IController).IsAssignableFrom(t)
select t.Name.Replace("Controller", ""));
var groupName = values["group"];
if (groupName != null)
{
if (controllerTypes.Any(x => x.Equals(groupName.ToString(),
StringComparison.OrdinalIgnoreCase)))
{
return false;
}
}
return true;
}
}
Register this constraint when you register your area route.
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Group_default",
"{group}/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { anything = new GroupNameConstraint() }
);
}
This should work assuming you will never have a groupName same as your controller name (Ex : Home )

How do I redirect to an other area in MVC3?

I have 3 areas at the moment (more will come when I get this working): Login, User and Admin. The Default route in Global.asax go to the index action of the index controller in the login area (Login\Index\Index) which works fine, this is how I mapped that:
routes.MapRoute(
"Default", // Route name
"{area}/{controller}/{action}/{id}", // URL with parameters
new { area = "Login", controller = "Index", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new[] { typeof(AppName.Areas.Login.Controllers.IndexController).Namespace }
);
each of the 3 areas is registered like this in the AreaRegistration files:
context.MapRoute(
"Admin_default",
"{area}/{controller}/{action}/{id}",
new { area = "Admin", controller = "Index", action = "Index", id = UrlParameter.Optional },
new[] { typeof(AppName.Areas.Admin.Controllers.IndexController).Namespace }
);
The Login controllers index action takes the users login details, looks up the type of user and redirects them to the appropriate area...... at least it should do. From what I can gather searching google, the correct way to redirect to a specific area is this:
return RedirectToAction("Action", "Controller", new { area = UserType });
which doesn't seem to work, it just redirects to Login\Controller\Action and I can't work out why.
In my attempts to work out what was happening I used this:
var url = Url.Action("Action", "Controller", new { area = "Admin" });
which produced the same Login\Controller\Action url.
Any help fixing this would be greatly appreciated
In the routes parameter, you just set new { area = "OtherAreaName" }.
EDIT
Oh, I see you already tried that. I suppose the name of that area is correctly referenced and correctly named in the class AreaRegistration class, like this?
public class AuthorAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Author";
}
}
// ...
}
Could it also be that you need authentication and you are being redirected to the login page?

How to use MapRoute with Areas in MVC3

I've got an Area in my web app called "Admin".
So, http://localhost.com/Admin goes to the Home Controller and Index Action in the Admin Area.
However, I want to be able to hit the Admin Home Controller and Index Action with the following Url:
http://localhost.com/Hello
I've got this as my attempt:
routes.MapRoute(
"HelloPage",
"Hello/{controller}/{action}",
new{area= "Admin", controller = "Home", action = "Index"},
new[] { typeof(Areas.Admin.Controllers.HomeController).Namespace });
As you can see I'm specifying the namespace and the area, but all I get is the routing error:
The view 'Index' or its master was not found or no view engine supports the searched locations.
It's not searching in the Admin area.
Any ideas?
Try this:
routes.MapRoute(
"HelloPage",
"Hello/{controller}/{action}/{id}",
new { area = "Admin", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And then add this to your Admin controller action:
if (!this.ControllerContext.RouteData.DataTokens.ContainsKey("area"))
{
this.ControllerContext.RouteData.DataTokens.Add("area", "Admin")
}
You can check here for further documentation.
The problem was that I was setting the route in Global.asax.
I should have been setting it in the AreaRegistration in the Admin area. Once I did that the problem was fixed.

MVC3 Route/redirect problem

My application is multilingual and I wrote the following route in order to handle the languages:
routes.MapRoute(
"Default", // Route name
"{language}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index",
language = "pt", id = UrlParameter.Optional }, // Parameter defaults
new { language = #"(pt)|(es)|(en)" }
);
This works for domain.com and domain.com/pt/home/index. However, if I type domain.com/home/index it fails (404).
The desired behavior would be it being redirected to domain.com/pt/home/index (pt is the default language).
Whats the best way to achieve this? I've been reading a lot about routes and ActionFilters but nothing seems quite right.
i would suggest using custom route handler like following
public class LanguageRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
IRouteHandler handler = new MvcRouteHandler();
var vals = requestContext.RouteData.Values;
if(vals["language"] == null)
{
vals["language"] = "pt";
}
return handler.GetHttpHandler(requestContext);
}
}
and have another route without language route value and set its route handler (global.asax)
routes.MapRoute(
"Default2", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
).RouteHandler = new LanguageRouteHandler();
This will not redirect Home/index to pt/home/index yet it will provide language = "pt" to your index action method (and all others). if you want to redirect you can implement an actionfilter but redirecting will create problems with post requests. For example when you post a form to /home/index and suppose it is redirected by action filter, the redirected request will lose posted form data
You need two routes, the other one without the language, or add the language parameter at the end
Try this
routes.MapRoute(
"Default", // Route name
"{language}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { language = #"(pt)|(es)|(en)" }
);
and modify your action in this way
public ActionResult Index([DefaultValue("pt")] string language)
{
...
}

How do I make this ASP.NET MVC Route for a twitter-style URL work?

trying to map the following style of route: http://site.com/username in the same way that you can do http://www.twitter.com/user
My initial solution was to have these routes:
//site.com/rathboma - maps to user details for rathboma
routes.MapRoute("Users", "{id}", new { controller = "Users", action = "Details" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "oneday" } // Parameter defaults
);
And that was working fine, until I tried to do the following in my 'Links' controller:
public ActionResult Details(string id)
{
int newId;
if (!int.TryParse(id, out newId))
return RedirectToAction("Index");
WebLink results = Service.GetWebLink(newId, 5);
if (results == null)
return RedirectToAction("Index");
return View(results);
}
These RedirectToAction methods try and return the browser to http://site.com/Users (I do have a users controller) instead of directing to http://site.com/Links/index
Why is this is happening?
How should I be organizing my routes to make this work properly?
I'm happy sacrificing http://site.com/links and moving to http://site.com/links/index if I have to. But how would I enforce that?
Thanks to all for any help
EDIT:
I know what's causing this, it's trying to redirect to http://site.com/links (the index page), but links is being picked up as a username and redirecting to /users/details, when it can't find the user 'links' it tries to redirect to the UsersController Index action which maps to /users, and the cycle continues ('users' is not a user it can find so redirects infinately).
So I guess My sub-question is: how to I make mvc always use /links/index instead of just using /links for the index page?
Try adding this route before your Users route:
routes.MapRoute("Links",
"{controller}/{id}",
new { controller = "Links", action = "Details" });
This should then work for
http://mysite.com/Links/id
&
http://mysite.com/username
I believe changing RedirectToAction("Index"); to RedirectToAction("Index", "Links"); in your Links controller should solve the issue without having to change your routes.
The problem is you have two very greedy routes. What I'd do is to break apart the default route to less greedy routes like this :
routes.MapRoute("Links",
"Links/{id}",
new { controller = "Links", action = "Index" });
routes.MapRoute("Users",
"{id}",
new { controller = "Users", action = "Details" });
routes.MapRoute("Default",
"",
new { controller = "Home", action = "Index" });
Causing the urls to be like the following :
site.com/links/5 - hits the Links controller
site.com/name - hits the Users controller
site.com/ - hits the home controller

Categories