Custom routes management - asp.net-mvc

Is it possible to use custom routes handling code?
For example client requests server on http://server.com/api/v1/json/profile/ and my code calls ApiController, MyAction action with parameters version=1, format=json, action=profile.

Something like this? You'll have to use a different parameter name for action so you don't have a conflict with the controller action.
.MapRoute("name", "api/v{version}/{format}/{_action}", new { controller = "ApiController", action = "MyAction" });
EDIT made version work the way you wanted.

I would start off by renaming the "action" parameter to something else otherwise the route is going to get very confusing (maybe call it purpose?). Also, I believe something like the following would work:
routes.MapRoute(
// name of your route
"MyRoute",
// route template
"api/v{version}/{format}/{purpose}",
// default route values
new {
controller = "ApiController",
action = "MyAction",
},
// constraints placed on parameters (make sure they are valid)
new {
version = #"^\d+$", // number only (can also include decimals)
format = #"^(json|text|xml)$", // if you want filtering...
}
);
Then:
public ApiController : Controller
{
public ActionResult MyAction(Int32 version, String format, String purpose)
{
throw new NotImplementedException();
}
}

Related

How can I set up a simple route with areas in ASP.NET MVC3?

I want to use Areas so I set up the following:
public class ContentAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Content";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Content_default",
"Content/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
What I would like is for a person who enters the following URL to be directed to a controller inside my Content area.
www.stackoverflow.com/Content/0B020D/test-data
I would like a person entering any URL with "/Content/" followed by six characters to be sent to:
- Page action in a controller named ItemController
- Six characters passed as the parameter id
- Optional text after that (test-data in this case) to be put into parameter title
How can I do this? I am not very familiar with setting up routes when using areas.
the six digits to be put into a variable called ID
So you're looking for something like
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Content_default",
"Content/{id}/{optional}",
new { controller = "ItemController", action = "TheActionYouWantThisToAllRouteTo" }
}
This would default everything to one controller and action method (which you have to specify in your instance). You can then get the data like so:
public ActionResult TheActionYouWantThisToAllRouteTo (string id, string optional)
{
// Do what you need to do
}
The way the routes are setup, you can name the pieces of information you want in a URL by wrapping it in a pair of { } curly braces. If you'd rather the name of optional to be isTestData then you would just change the route to read "Content/{id}/{isTestData}".
Note: Since you didn't specify the default action method you want this to route to, I substituted it with TheActionYouWantThisToAllRouteTo. Change that string to read the action method you want this to all go to. This also means you can't have a "regular" controller named ContentController, either.
Edit
Stephen Walther has a good blog post on custom route constraints. It can be found here. It should be a good start to get done what you need.

MVC routing with optional parameter

I have this route set up:
routes.MapRoute(
"home3", // Route name
"home3/{id}", // URL with parameters
new {
controller = "home",
action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
But in my controller I don't know how to get the optional id parameter. Can someone explain how I can access this and how I deal with it being present or not present.
Thanks
your can write your actionmethod like
public ActionResult index(int? id)
{
if(id.HasValue)
{
//do something
}
else
{
//do something else
}
}
How to avoid nullable action parameters (and if statements)
As you've seen by #Muhammad's answer (which is BTW the one to be accepted as the correct answer) it's easy to get optional parameters (any route parameters actually) into controller actions. All you you have to make sure is that they're nullable (because they're optional).
But since they're optional you end up with branched code which is harder to unit test an maintain. Hence by using a simple action method selector it's possible to write something similar to this:
public ActionResult Index()
{
// do something when there's not ID
}
[RequiresRouteValues("id")]
public ActionResult Index(int id) // mind the NON-nullable parameter
{
// do something that needs ID
}
A custom action method selector has been used in this case and you can find its code and detailed explanation in my blog post. These kind of actions are easy to grasp/understand, unit test (no unnecessary branches) and maintain.

How can I pass the URL to the controller while routing ignores it?

Is there a way within asp.net MVC 2 whereby I can route a request and have a portion of the URL ignored and passed to the controller as a variable?
My needs state that I must store pages dynamically in a database, and they should be accessible by looking at the URL and reading the URL segments to find the relevant page. Effectively, I need a Site controller, to which the remaining portion of the URL will be passed.
Site-Controller/this/is/a/page
So this in case the site controller would pick up the /this/is/a/page 'string'
Is this possible?
Thanks!
Yes, use a wildcard route, like:
routes.MapRoute(
"SiteController", // Route name
"Site-Controller/{*url}", // URL with parameters
new { controller = "SiteController", action = "Index" }, // Parameter defaults
null // constraints
);
Then your action looks like:
public ActionResult Index(string url)
{
}
Create a wildcard Route in Global.asax which captures everything after the first segment of the url and passes it to your Action method:
routes.MapRoute("Page",
"Site-Controller/{*urlsegments}",
new {
controller = "Site-Controller",
action = "YourAction",
urlsegments = ""
});
Make sure your Action method accepts a 'urlsegments' parameter and you can work with it from there:
public ActionResult YourAction(string urlsegments)
{
// Do something with the segments here
}

ASP.NET MVC Map String Url To A Route Value Object

I am creating a modular ASP.NET MVC application using areas. In short, I have created a greedy route that captures all routes beginning with {application}/{*catchAll}.
Here is the action:
// get /application/index
public ActionResult Index(string application, object catchAll)
{
// forward to partial request to return partial view
ViewData["partialRequest"] = new PartialRequest(catchAll);
// this gets called in the view page and uses a partial request class to return a partial view
}
Example:
The Url "/Application/Accounts/LogOn" will then cause the Index action to pass "/Accounts/LogOn" into the PartialRequest, but as a string value.
// partial request constructor
public PartialRequest(object routeValues)
{
RouteValueDictionary = new RouteValueDictionary(routeValues);
}
In this case, the route value dictionary will not return any values for the routeData, whereas if I specify a route in the Index Action:
ViewData["partialRequest"] = new PartialRequest(new { controller = "accounts", action = "logon" });
It works, and the routeData values contains a "controller" key and an "action" key; whereas before, the keys are empty, and therefore the rest of the class wont work.
So my question is, how can I convert the "/Accounts/LogOn" in the catchAll to "new { controller = "accounts", action = "logon" }"??
If this is not clear, I will explain more! :)
Matt
This is the "closest" I have got, but it obviously wont work for complex routes:
// split values into array
var routeParts = catchAll.ToString().Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
// feels like a hack
catchAll = new
{
controller = routeParts[0],
action = routeParts[1]
};
You need to know what part is what in the catchAll parameter. Then you need to parse it yourself (like you are doing in your example or use a regexp). There is no way for the framework to know what part is the controller name and what is the action name and so on, as you haven't specified that in your route.
Why do you want to do something like this? There is probably a better way.

Response.RedirectToRoute with an action specified

I wish to redirect to a route but also specify the action to run on that route's controller.
I tried this:
Response.RedirectToRoute("Login", new { action = "ChangePassword" });
The action looks like this:
public ActionResult ChangePassword()
{}
The route looks like this:
routes.MapRoute("Login", "Login/{action}", new { controller = "Login",
action = "Index" } );
The error I get is :
System.NotImplementedException: The method or operation is not implemented.
Can you see what I'm doing wrong?
I too had a hard time with this. I did this
Response.Redirect(Url.RouteUrl(new{ controller="controller", action="action"}));
Well, you only get NotImplementedException when something throws it. So look at the stack trace (Call Stack) and find the routine which threw it. When VS automatically implements an interface, for example, the body will throw this; you're expected to replace the implementation.
return Redirect(Url.RouteUrl(new { controller = "Controller", action = "Action" }));

Resources