An MVC 6 route does not perform as expected - asp.net-mvc

I have this route:
routes.MapRoute(name: "Trads",
url: "test_3000/{action}/{traditional}",
defaults: new { controller = "Test_3000", action = "Subset", traditional = UrlParameter.Optional });
And a Test_3000Controller with this method:
// GET: Test_3000/Subset?traditional=(Chinese Character)
public ActionResult Subset(string traditional)
{
if (traditional == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Test_3000 test_3000 = db.Test_3000.Find(traditional);
if (test_3000 == null)
{
return HttpNotFound();
}
return View(test_3000);
}
This URL works:
server/test_3000/subset?traditional=的
This URL does NOT work:
server/test_3000/subset/的
In the latter case, 'traditional' is null.
"Traditional" is a column in an SQL table.

Have you tried this
Routes.MapRoute(name: "Trads",
url: "test_3000/{action}/{traditional?}",
defaults: new { controller = "Test_3000", action = "Subset", traditional = UrlParameter.Optional });
Notice the ? on traditional.
Also
public ActionResult Subset(string traditional = null)
{ ... }
So that traditional is explicitly set as an optional

routes.MapRoute(
name: "ChBoPinCritCji",
url: "charbopopincrits/subset/{Char}",
defaults: new { controller = "CharBopoPinCrits", action = "Subset", Char = typeof(string) }
);
This MapRoute, which is first, now works.
Thanks for the attention.

Related

MVC custom URL routing

I have a route configured like
routes.MapRoute(
name: "Default",
url: "TEST/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
It works fine to redirect to respective controller and actions.
I want to add another redirection on TEST so that if somebody uses www.mysite.com/TEST, it should redirect www.mysite.com/Test/Home instead of giving 403- Forbidden: Access is denied error.
I'm trying like this but could not achieve it.
routes.MapRoute(
name: "AnotherDefault",
url: "TEST",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Basically, what I'm trying to do is to redirect from www.mysite.com or www.mysite.com/TEST to www.mysite.com/TEST/Home
To add to the confusion, I also had a physical folder TEST in my application root. Just wondering if keeping another web.config in there would solve? I tried but of no luck
Please advise what i'm missing here. Thanks
After some experiment I have found that the physical folder TEST is causing redirection rule to fail. I changed my route to TEST1 in URL instead of TEST, it worked. But, I can't rename TEST folder. Please advise
Please set the property RouteExistingFiles to true above the Route configurations
public static void RegisterRoutes(RouteCollection routes)
{
routes.RouteExistingFiles = true;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "TEST/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
This should allow you to keep the name of folder and also the route name to be "TEST". Let me know how it works out for you
Keep using the first route:
routes.MapRoute(
name: "Default",
url: "TEST/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
and add this in your Web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"></modules>
<handlers>
<remove name="UrlRoutingHandler"/>
</handlers>
</system.webServer>
We Can manage url routing by validate from database.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// here i pass my parameter like wwww.abc.com/country-state-city
routes.MapLocalizedRoute("SeoFriendlyUrl",
"{SeoFriendlyName}",
new { controller = "Company", action = "Index" },
new[] { "MigrationTest.Controllers" });
// it is default
routes.MapRoute( name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
public static class LocalizedRouteExtensionMethod
{
public static Route MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
{
return MapLocalizedRoute(routes, name, url, defaults, null /* constraints */, namespaces);
}
public static Route MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
var route = new clsRouteData(url, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0))
{
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
}
public class clsRouteData : Route
{
public clsRouteData(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData data = base.GetRouteData(httpContext);
if (data != null)
{
var SeoFriendliyName = data.Values["SeoFriendlyName"] as string;
if (SeoFriendliyName=="india-raj-jaipur")
{
data.Values["controller"] = "City";
data.Values["action"] = "Index";
// Can be send parameter
//data.Values["Id"] = Resutls.Id;
}
}
else
{
data.Values["controller"] = "Norecord";
data.Values["action"] = "Index";
// Can be send parameter
//data.Values["Id"] = Resutls.Id;
}
return data;
}
}

Optional id for default action

I got a site with only this Route:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Image", action = "Image", id = UrlParameter.Optional }
);
}
This is the controller:
public class ImageController : Controller
{
public ActionResult Image(int? id)
{
if (id == null)
{
// Do something
return View(model);
}
else
{
// Do something else
return View(model);
}
}
}
Now this is the default action so i can access it without an ID just by directly going to my domain. For calling the id it works just fine by going to /Image/Image/ID. However what i want is calling this without Image/Image (so /ID). This doesn't work now.
Is this a limitation of the default Route or is there a way to get this to work?
Thanks
Create a new route specific for this url:
routes.MapRoute(
name: "Image Details",
url: "Image/{id}",
defaults: new { controller = "Image", action = "Image" },
constraints: new { id = #"\d+" });
Make sure you register the above route before this one:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
Otherwise it will not work, since the default route will take precedence.
Here I'm stating that if the url contains "/Image/1" then the ImageController/Image action method is executed.
public ActionResult Image(int id) { //..... // }
The constraint means that the {id} parameter must be a number (based on the regular expression \d+), so there's no need for a nullable int, unless you do want a nullable int, in that case remove the constraint.

#Html.ActionLink returning a parameterised hyperlink

I am calling:
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"})
expecting
www.example.com/Account/Register
but I'm getting
http://www.example.com/?action=Register&controller=Account&area=FrontEnd
I'm a little confused as to why this happening, what can I do to resolve this?
Edit
When I remove the area parameter at the end, it builds the link correctly but to my admin section instead of FrontEnd.
Edit
I've isolated it to a custom route I have setup:
routes.Add("CategoriesRoute", new CategoriesRoute()); //This is breaking ActionLink.
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", area = "FrontEnd", id = UrlParameter.Optional },
new[] { "CC.Web.Areas.FrontEnd.Controllers" }
);
This is the custom route.
public class CategoriesRoute : Route
{
public CategoriesRoute()
: base("{*categories}", new MvcRouteHandler())
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
return null;
string categories = rd.Values["categories"] as string;
if (categories.IsEmpty())
return null;
string[] parts = categories.Split('/');
if (not a category) //pseudo code
return null;
rd.Values["controller"] = "Category";
rd.Values["action"] = "Index";
rd.Values["area"] = "FrontEnd";
rd.DataTokens.Add("namespaces", new string[] { "CC.Web.Areas.FrontEnd.Controllers" });
rd.Values["categoryString"] = "/" + categories; //Required to get exact match on the cache.
return rd;
}
}
Try the below. I think you're missing an attribute null at the end
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"}, null)
You need to add null for the 5th parameter (html attributes)
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"}, null)

MVC Creating Custom Routes

I have the following in my controller:
public ActionResult Details(string name)
{
Student student = db.Students.FirstOrDefault(x => x.FirstName == name);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
// GET: /Student/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
RouteConfig.cs:
// /Student/Details/Id
routes.MapRoute(
name: "StudentDetailsId",
url: "{Student}/{Action}/{id}",
defaults: new { controller = "Student", action = "Details", id = UrlParameter.Optional },
constraints: new { id = #"\d+" }
);
// /Student/Details/Name
routes.MapRoute(
name: "StudentDetailsName",
url: "{Student}/{Details}/{name}",
defaults: new { controller = "Student", action = "Details" }
);
// /Student/Name
routes.MapRoute(
name: "StudentName",
url: "{Student}/{name}",
defaults: new { controller = "Student", action = "Details" }
);
So pretty much I would like to have the same action name but fetched with either an id:int or string.
However I get the following:
The current request for action 'Details' on controller type 'StudentController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Details(System.String) on type MySuperAwesomeMVCApp.Controllers.StudentController
System.Web.Mvc.ActionResult Details(System.Nullable`1[System.Int32]) on type MySuperAwesomeMVCApp.Controllers.StudentController
Controller:
public ActionResult DetailsByName(string name)
{
Student student = db.Students.FirstOrDefault(x => x.FirstName == name);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
// GET: /Student/Details/5
public ActionResult DetailsById(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
Routes:
// /Student/Details/Id
routes.MapRoute(
name: "StudentDetailsId",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Student", action = "DetailsById", id = UrlParameter.Optional },
constraints: new { id = #"\d+" }
);
// /Student/Details/Name
routes.MapRoute(
name: "StudentDetailsName",
url: "{controller}/{action}/{name}",
defaults: new { controller = "Student", action = "DetailsByName" }
);
// /Student/Name
routes.MapRoute(
name: "StudentName",
url: "{controller}/{name}",
defaults: new { controller = "Student", action = "DetailsByName" }
);
In MVC, you can only have a maximum of 2 methods with the same name, and when you do, one of them must be GET and the other must be POST.
No, MVC cannot figure out which action method you want to invoke given a set of route data. Though your methods are valid C# overloads, MVC's action method selector is not strongly-typed. I have answered this question before, let me look up the link...
Update
Here is the link: https://stackoverflow.com/a/10668537/304832
Another Update
I only bring this up because other people have thanked me for mentioning it when I answer other routing questions.... Look into AttributeRouting.NET. It is so great that it's the most talked about feature of MVC5, though it started out as an open source side project and there is no reason why you can't use it in MVC4. Just download the NuGet package. With this library, you don't need to use MapRoute. Your action methods would look like this:
// GET: /Students/Details/5
[GET("students/details/{id:int}", ControllerPrecedence = 1)]
public ActionResult DetailsById(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
// GET: /Students/Details/Albert+Einstein
// or GET: /Students/Albert+Einstein
[GET("students/{name}", ActionPrecedence = 1)]
[GET("students/details/{name}")]
public ActionResult DetailsByName(string name)
{
Student student = db.Students.FirstOrDefault(x => x.FirstName == name);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
No MapRoute or cryptic regular expression constraints necessary. You just have to make sure your int method has precedence so that MVC doesn't try to pass numbers into your method that takes a string.

ASP.NET MVC - Strange routing issue, very simple route mismatch problem

I'm at a loss... here's my route:
routes.MapRoute("LangOnly", "{language}",
new { controller = "Home", action = "Root", language = "en" },
new { language = #"en|ja" });
it matches www.domain.com/en, but does not match www.domain.com/ja.
huh? I've even gone so far as to comment out any other routes... kind of stuck. ;/
Update: Here's the root action on the Home controller.
[CompressFilter]
public ActionResult Root()
{
if (!IsEnglish)
return RedirectToAction("Index", "Biz", new { b = "" });
return Request.IsAuthenticated ? View("LoggedInRoot") : View("Root");
}
It doesn't take a language parameter because it's being set on the base controller in OnActionExecuting, like so:
var l = (RouteData.Values["language"] != null) ? RouteData.Values["language"].ToString() : string.Empty;
if (string.IsNullOrEmpty(l))
l = "en";
if (l.Contains("en"))
{
IsEnglish = true;
l = "en";
}
else
{
IsEnglish = false;
l = "ja";
}
ViewData["lang"] = l.ToLower();
Language = l.ToLower();
Works perfectly for me with your route. Try this simple configuration:
routes.MapRoute("LangOnly", "{language}",
new {controller = "Home", action = "Index", language = "en"},
new {language = #"en|ja"});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
And your action:
public ActionResult Index(string language)
{
.....
(I am using "Index" as the action here, obviously change it to "Root" if that is in fact your action name.)

Resources