MVC MapRoute with parameter ticket-id - c#

I need to create a route with an url like: "{controller}/{action}/{ticket-id}"
routes.MapRoute(
name: "Login",
url: "Auth/Login/{ticket-id}",
defaults: new { controller = "Auth", action = "Login"}
);
I can't create the route because of the parameter name "ticket-id".
No problem with "ticketid"... but I can't change the parameter name.
Do you have any solutions.
Thanks

MVC MapRoute maps the parameter name in the template to the parameter names in the action.
You say that you can't change the parameter name. Problem is that in c# you would not even be allowed to use that parameter name.
c# does not allow you to have hyphens - for parameter/variable names.
This would not be allowed as names must be valid identifiers.
public ActionResult Login(string ticket-id ) {...}

Related

Route variables received as action variables?

I've got the following route configuration:
routes.MapRoute(
name: "Default",
url: "{project}/{version}/{controller}/{action}",
defaults: new { controller = "Portal", action = "Index" }
);
The idea is to have two custom parameters in the URL, before anything else so an action filter I created can do a few useful things. That works well so far, but here's the problem.
Here's an action method with a parameter called version
public ActionResult SomeMethod(string version)
{
//Some logic has been performed using the custom route variable values before getting in here....
}
If I do the following call: http:/server/RouteValue1/RouteValue2/MyController/SomeMethod?version=1
The value of the version parameter of SomeMethod is RouteValue2.
Is there any way to tell the framework not to do that? Keep route variables seperate from action variables ?
No, you can't use the same parameter name in both the route config and as a query string. You'll need to rename one, i.e.:
http:/server/RouteValue1/RouteValue2/MyController/SomeMethod?ver=1

Appropriate use of Html.ActionLink for a specific rule

I have this rule in the RouteConfig:
routes.MapRoute(
name: "UserProfile",
url: "users/{uid}",
defaults: new { controller = "Users", action = "Profile" }
);
How do I link to this action using #Html.ActionLink? It is easy enough to do it using #Html.Routelink but is it possible to do using the former?
You simply need to pass in the action name, controller name, and then an object that contains other route values, which in this case is uid
#Html.ActionLink("User Profile", "Profile", "Users", new { uid = 1 }, null)
If this doesn't translate into /users/{uid} because of how your routes are setup, then you should use #Html.RouteLink(). #Html.ActionLink() is for linking to an action directly. You provide the action and controller, and it gives a url based off of the routes that you have set up. If there are conflicting routes, you may not get the url you are expecting. In this case, linking to the route you want is the way to go.

Disambiguating RESTful services

I have used WCF extensively in previous projects. Lately, I have been exploring the use of ASP.NET Web API in creating RESTful services. After studying the DO's and DONT's of RESTful services and even trying it practically, I have a rather straightforward question.
Suppose I have a UsersController (inheriting ApiController) where I NEED to have 3 GET-type action methods:
GetUsers()
GetUserById(string id)
GetUserByName(string name)
Suppose I also have the following route in WebApiConfig
config.Routes.MapHttpRoute(
name: "Users",
routeTemplate: "api/users/{id}",
defaults: new { controller = "users", id = RouteParameter.Optional }
);
http://localhost:<port>/api/users would obviously invoke GetUsers()
The problem comes when I need to invoke either of the two action methods that take a single parameter.
I would like
http://localhost:<port>/api/users/5c6fe209-821e-475f-920d-1af0f3f52a82 to invoke GetUserById(string id)
and
http://localhost:<port>/api/users/jdoe to invoke GetUserByName(string name)
What I expect will happen instead is that I'll either get an error or only the first action method will be invoked for either case.
Since introducing the action on the route to disambiguate is considered as a deviation from pure RESTful services, how do I make the different URLs invoke the respective action method? I have scoured the web and most examples of RESTful services (by purists) stop at a first action method to retrieve everything and a second to retrieve a single item.
This can be achieved using more specific constrained routes. The example below is similar to what you are trying to achieve:
config.Routes.MapHttpRoute(
name: "ById",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetById" },
constraints: new { id = #"\d+" }
);
config.Routes.MapHttpRoute(
name: "ByName",
routeTemplate: "api/{controller}/{name}",
defaults: new { action = "GetByName", },
constraints: new { name = #"\w+" }
);
config.Routes.MapHttpRoute(
name: "All",
routeTemplate: "api/{controller}",
defaults: new { action = "GetAll", }
);
The constraints object you pass to MapHttpRoute specifies constraints in the form of regex for the different URL parameters. In this example, for the ById route we only match if the id parameter is a number. We only match ByName if the name parameter is a string of alpha characters. We match All on no parameters. Note the "+" on each of the regex specifies no empty values. Routes are matched in the order they are defined, so you should put the least specific rules below more specific rules.
In your case, you will need to find or write a regular expression that matches the GUID format you are using and constrain your ById route to match this expression. You'll then want to define your ByName route below accepting any string. Because it's below, it will only get called if the input string is not a GUID.
I should also add that if you have not worked with MVC routes before, they are very specific. You'll notice that the name of my parameter is {id} for ById and {name} for ByName. It is important these parameters match the exact name of your input parameter on your controller method since it's this that is used by the router build the method call. Even if you have only a single parameter on an action, if the name is not mapped correctly you'll get an error.

how to obsolete controller name from Html.ActionLink in mvc3

I want to obsolete controller name from Html.ActionLink
because I defined my controller in route how to do this,
because if I leave controller name blank in Html.ActionLink
mvc3 automatically put current controller name in Action Link.
If you named your route, you can use RouteLink instead of ActionLink.
You'll only have to specify the name of the route, not the controller.
Here's an example of a named route:
routes.MapRoute( "myRoute",
"doStuff/Now",
new {controller = "MyController", action = "DoIt"} );
And here's how to use it in your view
Html.RouteLink( "Do it!", "myRoute" );
Please see MSDN for full details on RouteLink.

How to define this route in ASP.NET MVC?

I have a controller named Movie, with an action named ByYear, which takes the year as a parameter :
public ActionResult ByYear(int year)
{
ViewData["Title"] = string.Format("Movies released in {0}", year);
var repository = MvcApplication.GetRepository();
var movies = repository.Medias
.OfType<Movie>()
.Where(m => m.Year == year);
return View("Index", movies);
}
I'd like to access this action with the following URL : /Movie/ByYear/{year}, but the only valid route for this action is this : /Movie/ByYear?year={year}.
I tried to add new routes in my application's RegisterRoutes method, but I can't find a way to get the desired result...
Could anyone tell me how to achieve that ?
Note: this is actually very similar to this question, but no answer was accepted, and the highest voted answer makes no sense to me as I'm completely new to MVC...
Change the name of your parameter year to id and this will match the default route that MVC adds to your project.
So for further clarification, let's take a look at the default route added by ASP.NET MVC:
routes.MapRoute(
"default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
In this route you can see three tokens that are named specifically for controller, action, and the third token which is passed to the action is id. When a request comes into your application, ASP.NET MVC will analyze the routes that are currently mapped and try to find a method signature that matches them by using reflection against your controllers.
When it looks at your Movie controller, it sees an action called ByYear, however that method takes an integer called year, not id. This is why you end up with something like /Movie/ByYear?year={year} when you create an ActionLink for that particular Action. So to fix this, you have two options:
The first and most simple method to fix this is to just change the method signature for your Action to accept a parameter named id which is what I recommended above. This will work fine, but I can see where it might cause a little bit of confusion when you go back to that source later and wonder why you called that parameter id.
The second method is to add another route that matches that method signature. To do this, you should open your Global.asax and just add the following (untested, but should work):
routes.MapRoute(
"MoviesByYear",
"Movies/ByYear/{year}",
new { controller = "Movie", action = "ByYear" }
);
This route is hard-coded, yes, but it won't break the other routes in your system, and it will allow you to call the method parameter year.
EDIT 2: Another thing to note is that the routing engine will stop on the first route it finds that matches your request, so any custom routes like this should be added before the default route so you are sure they will be found.
OK, I just found out how to do it. I just had to create the new route before the default route... I didn't think the order had any significance
routes.MapRoute(
"MovieByYear", // Route name
"Movie/ByYear/{year}", // URL with parameters
new { controller = "Movie", action = "ByYear" } // Parameter defaults
);
EDIT: Isn't there a simpler way ? (not involving renaming the parameters). I'd like to be able to do something like that :
[Route("/Movie/ByYear/{year}")]
public ActionResult ByYear(int year)
{
...
Design considerations aside, if you did not want to rename the parameter, you could add something like the route below, which enforces having the year parameter
routes.MapRoute(
"MovieByYear", // Route name
"Movie/ByYear/{year}", // URL with parameters
new { controller = "Movie", action = "ByYear" },
new { year = #"\d+" } // Parameter defaults
);

Categories