MVC Default route with nullable id not working as expected - c#

A simple routing scenario is not working for me.
my route registration looks like this
context.MapRoute(
"Users_default",
"Users/{controller}/{action}/{id}",
new { action = "Index", id= UrlParameter.Optional });
and i am expecting it to honor the requests for
users/profile/
users/profile/1
users/profile/2
with the following controller
public class ProfileController : Controller
{
public ActionResult Index(int? id)
{
var user = id == null ? (UserModel)HttpContext.Session["CurrentUser"] : userManager.GetUserById((int)id);
return View(user);
}
}
it works for users/profile but not for users/profile/1
i've tried few different things but i know the answer must be simple, its just my lack of knowledge, what am i missing here.

i dont want index to appear. i want to use the same method for both users/profile/1 and users/profile/
Then don't put action into your URL.
context.MapRoute(
"Users_default",
"Users/{controller}/{id}",
new { action = "Index", id= UrlParameter.Optional });
The route you have defined will not allow index to be optional because it is followed by another parameter (in this case "id"). Only the last parameter can be optional on all but the default route.

This is because your route interprets as:
{controller: "profile", action: "1"}.
You need to point you details action url explicit, something like this:
users/profile/index/1

You can use Attribute routing
The code would look like
public class ProfileController : Controller
{
[Route("users/profile/{id}")]
public ActionResult Index(int? id)
{
var user = id == null ? (UserModel)HttpContext.Session["CurrentUser"] : userManager.GetUserById((int)id);
return View();
}
}
And you have to modify your RouteConfig
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// This will enable attribute routing in your project
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
So now you can use users/profile for your default behaviour and users/profile/ for a specific profile.

Related

check second parameter in asp.net

I am new in c# mvc, and I am trying to make a route with multiple parameters that looks like this:
controller/action/parameterOne/parameterTwo
but in some cases I'm gonna just use one of them so the route will look like this:
controller/action/parameterOne
here is my RouteConfig.cs
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 }
);
routes.MapRoute(
name:"Default2",
url: "{controller}/{action}/{category}/{id}",
defaults: new { controller = "Home", action = "Index", category = UrlParameter.Optional, id = UrlParameter.Optional }
);
}
now in my controller's action I need to check if there is only one parameter or two so I can return a different view for each condition, here is the controller:
[HttpGet]
public ActionResult someAction(string category, string id)
{
if (String.IsNullOrWhiteSpace(id))
{
return View("viewOne");
}
else
{
return View("ViewTwo");
}
}
the problem is that the if statement is not full working? because if the conditoin is this: String.IsNullOrWhiteSpace(id)
and if I write controller/action/parameterOne this return the ViewOne
but if I write controller/action/parameterOne/parameterTwo also return the ViewOne
but now if a invert the condition and I write !String.IsNullOrWhiteSpace(id) both urls return ViewTwo.
So does any one have any idea why is that happening?
Do you have any objection to only using the default route? The only drawback that comes to mind is if you really want your url to look a certain way in which case you may need to define multiple routes as youre trying to do. However, the following should work with only the default route:
//note controller actions will default to HttpGet if no data annotation is explicitly supplied. Also, action names generally begin uppercase by convention
public ActionResult SomeAction(string category, string id = null)
{
if (String.IsNullOrWhiteSpace(id))
{
return View("viewOne");
}
else
{
return View("ViewTwo");
}
}
the various requests you mentioned would look like:
www.myhost.com/controller/someaction?category=parameterOne&id=parameterTwo
or
www.myhost.com/controller/someaction?category=parameterOne

ASP.NET Passing Parameter in URL

I wrote a very simple web app in Flask and am porting it to ASP.NET Framework. All the functionality is in JavaScript and HTMl, so the framework should just act as scaffolding. I've got almost everything ported over, except for what seems to be a routing issue. My site expects a string token variable to be appended to the URL, like so: www.mysite.com/token-string. For development, the URL is localhost:*****/string-token, with my Index.cshtml page being displayed as default.
When I pass the URL without the token it works fine and my index page loads. However I get a 404 when I try it with the token. I'm assuming it's identifying the token as a route and is trying to navigate to it? I'm not sure how to fix it. Here are the important parts of my code:
HomeController.cs:
public class HomeController : Controller
{
public ActionResult Index(string token)
{
return View();
}
}
RouteConfig.cs:
NB: I've not changed this, not sure what to do with it.
public class RouteConfig
{
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 }
);
}
}
It's quite important that the token is passed in the way it is, rather than as a ? query parameter or anything like that. Additionally, the C# index view doesn't really need to do anything with the token - it gets extracted by the JavaScript.
Any advice is most welcome. Thanks.
Each segment (i.e. {controller}) in the route is a variable, and in the default route makes them all optional. Therefore, your default route is matching the request www.mysite.com/token-string.
What you need to do is insert a route that has a constraint to only match URLs with your token. Assuming your token is a GUID, you could use a regex route constraint as follows:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "TokenRoute",
url: "{token}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { token = #"^[0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12}$" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
If your token is not a GUID, you could either use a different regex or implement IRouteConstraint to ensure the route only matches your tokens. The logic you use could be as simple as a == statement (as shown) or more complex (such as a database lookup).
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "TokenRoute",
url: "{token}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { token = new TokenConstraint() }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
public class TokenConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if ((string)values[parameterName] == "MyToken")
{
return true;
}
return false;
}
}
Note that you should use the route value key {token} in the url: parameter to match the action method parameter name token.
public ActionResult Index(string token)
{
return View();
}
I guess you could try changing the default route to include token instead of id as shown below.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{token}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The default Route pattern which you have expects the parameter with name as 'id'
Either add (or modify the default route) like below route pattern
routes.MapRoute(
name: "AnotherRoute", //your desired route name
url: "{controller}/{action}/{token-string}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

ASP.NET MVC 5 route config

I have 2 routes:
college/{courseId}/{classId}
college/{courseId}
But sometime when I try to input the 1st url type like college/course1/class2, it go to the 2nd action.
Can I fix route configuration to do it exactly? Here is my code:
[Route("college/{courseId}/{classId}")]
public void ActionResult example1(string courseId, string classId) {
return View();
}
[Route("college/{courseId}")]
public void ActionResult example2(string courseId) {
return View();
}
RouteConfig.cs file:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
AreaRegistration.RegisterAllAreas();
routes.MapMvcAttributeRoutes();
//Default
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
This may be helpful to you.
https://www.nuget.org/packages/routedebugger/
It will show you what routes are matched.
I suspect that they both are matched but are added in the incorrect order.
It may be as simple as inverting the order in which they are adding or making them more specific. ( making the params required)
I recommend you to define only one route and have only one action with an optional parameter:
[Route("college/{courseId}/{classId?}")]
public void ActionResult example1(string courseId, string classId) {
// Do classId null check if necessary
return View();
}
Please notice, there is a question mark after classId parameter in route definition.

Direct route to custom search with MVC

I need to create a custom route with MVC to build a custom search:
Default Home's Index's Action:
public virtual ActionResult Index()
{
return View();
}
And I would like to read a string like this:
public virtual ActionResult Index(string name)
{
// call a service with the string name
return View();
}
For an URL like:
www.company.com/name
The problem is that I have this two routes but it's not working:
routes.MapRoute(
name: "Name",
url: "{name}",
defaults: new { controller = "Home", action = "Index", name = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", area = "", id = UrlParameter.Optional }
);
This way, any controller other then Home is redirected to Home, and if I switch the order, it can't find the Index Home Action.
You can use attribute routing for this. You can see the details about the package here. After installing the attribute routing package. Now a days it is installed by default for MVC5 application. Change your action method as below:
[GET("{name}")]
public virtual ActionResult Index(string name)
{
// call a service with the string name
return View();
}
Here's a catch for the code above:
The router will send the requests without the name also to this action method. To avoid that, you can change it as below:
[GET("{name}")]
public virtual ActionResult Index2(string name)
{
// call a service with the string name
return View("Index");
}

How to add a MapRoute like example.com/id

I want to create a URLs shortener website. URLs that I offer are like example.com/XXX where
XXX is the value of the short URL.
I want to have website on example.com and URLs are example.com/xxx. I want to get xxx from URL and redirect users to equivalent URLs in database.
How can implement this?
Create a new route in your RouteConfig for example:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("empty",
"{id}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
And the simply go to your database with the id passed in the index
public ActionResult Index(int id)
{
//Do Stuff with db
return View();
}
asp.net mvc documentation here.
One way you be doing the needed redirection in the default controller action. By default in asp.net mvc it is home/index.
So in the index action you should be having such code
public ActionResult Index(string id)
{
var url = Db.GetNeededUrl(id);
return Redirect(url);
}
So now if the user enters such an address site.com/NewYear you'll get redirected to the equivalent url that is in you database.

Categories

Resources