Cutom Routing in MVC Razor URlHelper.Action Path Issue - c#

I have Custom routing for my application as shown bellow
Application Name is ValidationTest and i do changed my default binding to following .
That works fine , But i do have some Actions in Controller class , and i do use urlHelper to Identify the Action Path and Controller path You can see that in the Bottom code , But after i changed the default routing it throws me exception While trying to read action from url helper , and i am new to mvc so please suggest me how to give the path to Controller and Action
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"MyRout",// Route name
"RubinsApp/{CRM}/{id}",// URL with parameters
new {
controller = "Render",
action = "RenderApp",
id = UrlParameter.Optional
} // Parameter defaults
);
}
so my url is
http://localhost/ValidationTest/RubinsApp/crm/test
so
ValidationTest=Application Name
RubinsApp/CRM =Routing Para
test=id
and this works Fine
My Problem is, I have an Ajax Action Call Where The Action URl was Defined Like Bellow
in cshtml
UrlHelper urm = new UrlHelper(Request.RequestContext);
var urlsMenu = urm.Action("BuildNavigationMenu", "Render").ToString(); //This Thorws Object null Error
Here
BuildNavigationMenu=Action Name
Render= Controller

In your custom route you have removed the {action} token meaning that you can no longer specify any other action than the one defined by default which is RenderApp. That's why the urlHelper.Action method returns null.
The way you have defined your routes, in this application you could only ever execute a single action (RenderApp) on a single controller (Render). In your urlHelper.Action call you are attempting to invoke the BuildNavigationMenu action but obviously that's impossible as this action can never be reached.
So you will have to modify your "RubinsApp/{CRM}/{id}" route to include at least the {action} token somewhere. Or add another route definition after it.
And just a side-note about your code. If you are writing this inside a controller action you don't need to instantiate a new UrlHelper. The Controller class already has a Url property:
public ActionResult Foo()
{
var urlsMenu = Url.Action("BuildNavigationMenu", "Render");
...
}

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

Set action name as route attribute automatically in ASP.NET Web API 2

I just checked attribute routing in ASP.NET Web API 2. In that I can use RoutePrefix attribute at class level to set prefix to all action name URL. Mostly I use action name as URL routing for particular action. Is there any way that I write a single line of code which set action name as default value for Route attribute for all action? I want that because I am using action name as URI template, so it will be duplication on top of each action name.
[RoutePrefix("api")]
//[Route("{action}")] // Possible I could write like this
public class BooksController : ApiController
{
[Route("GetBooks")] //Route value same as action name, http://localhost:xxxx/api/GetBooks
public object GetBooks() { ... }
[Route("CreateBook")] //Route value same as action name, http://localhost:xxxx/api/CreateBook
[HttpPost]
public object CreateBook(Book book) { ... }
}
EDIT 1: I want to use attribute routing because I want web API URL pattern like this http://hostname/api/action_name. My application uses single API controller, so I don't want controller name as part of action URI.
Solution: [Route("{action}")] on class level will work, if you remove route attribute from all other action unless you want to override for any action.
Personally I would just not use attribute routing and instead use the standard route mapping. So in your App_Start/RouteConfig.cs file:
routes.MapRoute(
name: "Api",
url: "api/{action}",
defaults: new { controller = "Books" }
);

RedirectToRoute causes redirect loop

public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToRoute("Home");
}
I expect this action to redirect the user to the homepage but instead, a redirect loop occurs (according to Chrome).
The aforementioned action belongs to a controller in the "admin" area as where the "Home" route is defined for the default area - I suspect this to be relevant.
Here is the route for good measure:
routes.MapRoute(
"Home",
"{controller}/{action}/{slug}",
new { controller = "Posts", action = "Index", slug = UrlParameter.Optional },
new[] { "GoBlog.Controllers" }
);
Update
Replacing the return statement with the following will cause the action to work as expected:
return RedirectToRoute("Home", (RouteTable.Routes["Home"] as Route).Defaults);
I want to know why this is the case. Ideally I can omit the (cumbersome) second argument.
This issue is particular to the call RedirectToRoute(string) and your particular route:
routes.MapRoute(
"Home",
"{controller}/{action}/{slug}",
new { controller = "Posts", action = "Index", slug = UrlParameter.Optional },
new[] { "GoBlog.Controllers" }
);
What you expected was RedirectToRoute would populate your arbitrary route definition of {controller}/{action}/ with the route's defined defaults:
controller = "Posts", action = "Index"
But RedirectToRoute like all redirect methods, is a part of your controller, and uses your current Controller and Action as Default Values where ever possible. This is a "feature" of the ASP.NET MVC framework -- re-using routes to create new routes. This approach is valuable because your current Controller and Action are strong hints as to your intention.
A great example of this is RedirectToAction(string) which assumes your current instantiated Controller is the default.
Contrast this with:
return RedirectToRoute("Home", (RouteTable.Routes["Home"] as Route).Defaults);
Rather than directing the framework to use it's best guess about how to populate the ambiguous wild card route, you have specifically instructed the framework to use the Defaults from the RouteTable for "Home" route to construct a route and return it as a RouteObject.
When you call RedirectToRoute(string)
This method converts the route name that is passed in routeName to a URL by using the RouteCollection.GetVirtualPath method.
where pass null as parameter RouteValueDictionary. So in this case this parameters was getting from current RequestContext with values for controller, action and etc, i.e. you get url like this
"{controller}/{action}/{slug}"
"Login/Logout/"
and got redirecting loop.
when you call
return RedirectToRoute("Home", (RouteTable.Routes["Home"] as Route).Defaults);
instead RedirectToRoute(string) used RedirectToRoute(String, RouteValueDictionary) and in RouteCollection.GetVirtualPath method you pass defaults values for that route.
It is a general best practice in MVC to allow your controllers as much control as possible. There are multiple controller methods which you can use, and you should generally use the one that is the closest fit to the process you are performing.
return View(). tells the controller to generate and return the specified HTML, similar to a Server.Transfer(). Use for matching HTML with Actions, or when delivering static HTML without interest in the URL string.
Return RedirectToAction(). Tells the controller to build a new URL string based on the Action. This will parse the route dictionary for the Action, and handle the defaults. It acts as a Response.Redirect(), and will return a new generated URL. In general, this is the most commonly used redirect. This also has the benefit of not changing if the route dictionary is changed.
return RedirectToRoute(). Similar to RedirectToAction(), however tied to the Route Dictionary. This will search the Route Dictionary for an exact route match, using whatever route parameters are passed. This does not look for Actions, and thus does not build a route or inject default values. Used when an exact route with specific non-default values must be processed.
return Redirect(). This redirect requires a full URL, and will redirect to the new URL. Usually used when redirecting to a URL on a totally different domain.

ASP MVC Simple View not working

I set up a Route in a standard MVC router in global.asax, using MapRoutes. looks like this
routes.MapRoute(
null, //route name
"AddUnregisteredUser/{phonenumber}", //params
new { controller = "User", action = "AddUnregisteredUserFromPhoneNumber" }
);
UserController.AddUnregisteredUserFromPhoneNumber returns a View that displays two ViewData["key"] values...
whenever i debug the project, and call LOCALHOST:PORT/AddUnregisteredUser/1234567890 I get nothing. I put breakpoints in teh controller function and its not even going to the controller function. I put breakpoint in the global.asax and it never sets up the route when starting the asp.net development IIS server....
I dont see what is wrong with my code. any help would be appreciated.
Try supplying a route name instead of null.
Also, you might want to use RouteDebugger from RouteMagic to verify your route definition.
You need to supply a route name as well as add phonenumber to your route values as follows:
routes.MapRoute(
"route1", //route name
"AddUnregisteredUser/{phonenumber}", //params
new { controller = "User", action = "AddUnregisteredUserFromPhoneNumber", id = UrlParameter.Optional}
);

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