route.GetRouteData(httpContext).Values["action"] is null for Attribute Routing - asp.net

What I'm trying to do it to get the controller name and action name in an HttpModule.
In the OnBeginRequest of my http module, I have the following code:
foreach (var route in RouteTable.Routes)
{
if (route.GetRouteData(httpContext) != null)
{
Console.WriteLine(string.Format(CultureInfo.InvariantCulture,
"Route info ====== {0}, {1} ======",
route.GetRouteData(httpContext).Values["controller"],
route.GetRouteData(httpContext).Values["action"]));
}
}
If the route is register using conventional routing like this:
routes.MapRoute("BlogDetails", "blog/{blogId}", new { controller = "Blog", action = "Details" });
And when I go to: ~/blog/1 I could see the output
"Route info ====== Blog, Details ======"
But if it's register using:
routes.MapMvcAttributeRoutes();
And in the controller I have:
[RouteArea("blog", AreaPrefix = "blog")]
[Route("{action}")]
On the action I have:[Route("{blogId}", Name="blogDetailRoute")]
And when I go to: ~/blog/1 I only see the output
"Route info ====== Blog, ======"
The action name is missing in that route data.
Anything is different in the attribute routing? Where could I find the action name?
Thanks for helping out!

The routes for attribute routing are stored in a nested IEnumerable<RouteData> named MS_DirectRouteMatches.
var routeData = routes.GetRouteData(httpContext);
if (routeData != null)
{
if (routeData.Values.ContainsKey("MS_DirectRouteMatches"))
{
routeData = ((IEnumerable<RouteData>)routeData.Values["MS_DirectRouteMatches"]).First();
}
}
This example shows how we take the regular route data if it matches the current context, and replace it with attribute routing data if it happens to exist.

Related

Wrong URI after Form Submit MVC 3 asp.NET

I'm a little confused on something here. I have a form, and the URL for that form is:
http://domain.com/Home/requestquote
When I click submit on a form and the method handling this form located in the form controller sends back a view, the URI looks like this:
http://domain.com/form/requestQuoteSubmit where requestQuoteSubmit is the method.
This occurs both when validation sends the page back for errors and when there is a successful form submit.
On success the view being sent back is Home/thanks and on error it should just send back Home/requestquote. Everything seems to work fine except for the fact that the URI is not what it is supposed to be. This causes everything else on the page to break because my links look like this:
#Url.RouteUrl(Model.CompanyPageDatabaseModel.companyCode, new { Controller = MVC.services.Name, Action = MVC.services.ActionNames.page })
So that companyCode value isn't being passed around properly and forming the links correctly. I'm not sure how or why the form method is sending back the correct page, but setting the URI to itself?
Here are my routes.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
null,
"{action}",
new { controller = MVC.Home.Name, action = MVC.Home.ActionNames.Index },
new { RootAction = new RootActionConstraint() } // Route Constraint
);
routes.MapRoute(
null, // Route name
"{controller}/{action}", // URL with parameters
new { controller = MVC.Home.Name, action = MVC.Home.ActionNames.Index }, // Parameter defaults
new { controller = "Home|contact|franchise|form|resources|services|technology|community|careers|carriers|about" }
);
routes.MapRoute(
null,
"{companyCode}/{action}",
new { controller = MVC.Home.Name, action = MVC.Home.ActionNames.Index },
new { RootAction = new RootActionConstraint() } // Route Constraint
);
routes.MapRoute(
"jax",
"{companyCode}/{controller}/{action}",
new { controller = MVC.Home.Name, action = MVC.Home.ActionNames.Index }
);
The last route value is an example of a franchisee route.
Also here is the form code in the view:
#using (Html.BeginForm("requestquote", "form", FormMethod.Post))
{ }
Any ideas?
Thanks.
Edit: Added in my routes.
There is a concept referred to as PRG, which stands for Post-Redirect-Get.
The basic idea is that you Post the form to your application. After processing the input, you then Redirect to a Get request at the correct URL, instead of serving the user a content response directly from the submission.
This is good for many reasons, but the underlying one is separation of concerns. (When you don't separate concerns weird stuff like all the links might breaking on your page tends to happen...)
So, the solution for you is to process the submission, and if invalid, store your Validation content in TempData and return a RedirectToRouteResult(controller:"Home",action:"RequestQuote")
Update: I found the original article I read to learn this concept. It's in terms of the original ASP.NET MVC release, but it should be mostly the same. Check out http://www.eworldui.net/blog/post/2008/05/ASPNET-MVC---Using-Post2c-Redirect2c-Get-Pattern.aspx

How do I create a route for matching all paths starting with a given prefix?

In my MVC application I want to create a route such that when a user requests a URL starting with a prefix some specific action is invoked.
For example, I want a route that would map processData{whatever} onto an action so that when a user requests processData, processData.asmx or processDataZOMG or whatever else with processData prefix that action is invoked.
I tried the following route
routes.MapRoute(
#"ProcessData", #"processData*", //<<<< note asterisk
new { controller = #"Api", action = #"ProcessData" } );
but it doesn't match processData and anything with that prefix - route matching falls through and the request is redirected to the main page.
How do I make a route that matches all paths with a specific prefix onto a specific controller-action pair?
Try the following: Update: This solution does not work, please refer to the solution I offer in my comment to this answer.
routes.MapRoute(
#"ProcessData", #"processData/{*appendix}", //<<<< note asterisk
new { controller = #"Api", action = #"ProcessData" } );
You could use route constraints:
routes.MapRoute(
"ProcessData", // Route name
"{token}", // URL with parameters
new { controller = "Api", action = "ProcessData" }, // Parameter defaults
new { token = #"^processdata.*" } // constraints
);

Default value for parameter in Controller Method is overriding everything

Hello i have just started learning mvc2 and im having a problem with the default value for the parameter page(you can see the method below).
Its always 0 regardless of what i type in the URL. For example this
h.ttp://localhost:52634/Products/List/2
should show page 2 but when in debug mode the page parameter is 0, so im always getting the first page of the list in my view.
i am using the predefined standard routes in global asax when you start a new mvc2 project.
am i missing something?
//This is the ProductsController
public ViewResult List(int page = 0)
{
var products = productsRepo.Products()
//send in source, current page and page size
productList = new PagedList<Product>(products, page, 10);
return View(productList);
}
It's a routing issue, the default route specifies an id property, you're using a property called page. I'm new to MVC myself, but add this route before the default route:
routes.MapRoute("MyRoute", "{controller}/{action}/{page}",
new { controller = "Foo", action = "List", page = UrlParameter.Optional });
Remove the " = 0", and do:
public ViewResult List(int? page)
{
int val = page.GetValueOrDefault(0);
And use val everywhere instead of page. That should work. If not, it's an issue with routing.
HTH.
I know it's very late to answer. As default route for MVC is following
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
which is expecting that parameter name should be id. Now you have 2 options here either change your parameter name to id or the other option is define your own route in route.config file which is under App_Start folder.

ASP.NET - ActionResult parameter is coming back null always when passing string - why?

I am barely starting out with my first project on the ASP.NET MVC project type and I am creating a Details page where instead of passing the templated (int id), I would like to pass a string instead. But when I am in debug mode, and enter this in the URL, "myString" is null. Why so? Do I have to change anything else somehwere else?
So if I go to the URL and enter this:
http://localhost:2345/Bank/EmployeeDetails/3d34xyz
public ActionResult EmployeeDetails(string myString) // myString is null
{
return View();
}
In you Global.asax.cs file, you will have the following route mapped by default:
routes.mapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
That means that an url like http://localhost:2345/Bank/EmployeeDetails/3d34xyz will go to the Bank controller, the EmployeeDetails action and pass the value 3d34xyz into a parameter named id. It is perfectly alright to pass a string, but in order to make it work you have two options:
1) Rename the variable to id in your action method.
public ActionResult EmployeeDetails(string id) { ... }
2) Add another route that matches whatever name you want for your string. Make sure to make it more specific than the default route, and to place it before the default route in the Global.asax.cs file.
routes.mapRoute(
"BankEmployeeDetails"
"Bank/EmployeeDetails/{myString}"
new { controller = "Bank", action = "EmployeeDetails", myString = UrlParameter.Optional });
This will pass a default value of null to myString if no value is passed in the url, but with the url you specified you will pass the value 3d34xyz.
Rename myString to id if you are using the default route table.
Assuming you haven't modified the default routes (In your Global.asax.cs):
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
The method is expecting it to be named "id".
Change the name of myString to id.
I had the same problem, you just need to provide the id in the page where you the hyperlink for Details(in the Bank page here)
#Html.ActionLink("Details", "Details", new { id=""})
This solved my problem hope it helps you.
This for MVC 5.
And when you have tryed all of them and still it comes back null then give a full restart for Visual Studio. That's what eventually helped for me.

How to hide controller name in Url?

How to hide controller name in Url?
I use the ASP.NET MVC.
The original url is: http://www.sample.com/Users.mvc/UserDetail/9615
The "Users" is controller name, the "UserDetail" is action name, and the "9615" is UserId.
How can I hide the controller name and action name in the url.
Just like this: http://www.sample.com/9615
I have writed the following code in the Global.ascx.cs to hide the action name:
routes.MapRoute(
"UserDetail", // Route name
"Users.mvc/{UserId}", // URL with parameters
new { controller = "Users", action = "UserDetail", UserId = "" } // Parameter defaults
);
Using the above code I hid the action name and got this url: http://www.sample.com/Users.mvc/9615
But how can I hide the controller name and get this url: http://www.sample.com/9615
Thanks.
The idea is the same. You do just the thing you did to the action. However, your problem arises from the fact that IIS is probably not mapping www.xyz.com/1234 to ASP.NET runtime. To do so in IIS7, enable integrated mode and in IIS6, add a wildcard mapping in handler map that maps everything to ASP.NET.
To add a wildcard map, see http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx (Search for "IIS6 Extension-less URLs" in that page)
After that, simply add a route:
routes.MapRoute("UserDetails", "{UserID}/{*name}",
new { controller = "Users", action = "UserDetail" , UserID=""});
This should do the trick.
MVC recognizes the difference between "{UserID}" and "{id}" so if you are going to have a route with only "{UserID}" in the Url you need to place it first in the list other wise it never gets hit. And make sure the default includes "id" since it will continually loop over "UserDetails" unless the default references id as apposed to UserID. I found this format works for me:
routes.MapRoute("UserDetails",
"{UserID}",
new { controller = "Users", action = "UserDetail", id = "" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Account", action = "LogOn", id = "" } // Parameter defaults
);

Resources