ASP.NET MVC 3 – How can I route directly to an action - asp.net-mvc-3

I have a controller called HomeController with the actions Index(), MethodOne() and MethodTwo(). Each of these just return View() for now.
When I create an action link with the code:
#Html.ActionLink("Home", "Index", "Home")
I get the hyperlink:
Home
This is good however using the same ActionLink extention method to route too MethodOne I get the hyperlink:
MethodOne</li>
What do I need to configure so my site will accept the hyperlink “/MethodOne”, this currently returns a 404.
I have a suspicion this may be related to routing. My routing table is currently the default:
routes.MapRoute("Default", "{controller}/{action}/{id}",
new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});

You need a route like:
routes.MapRoute(
"MethodOne", //Your route name.
"methodone", //What your browser/user will see at the URL bar: localhost.com/methodone
new { controller = "Home", action = "MethodOne" } //What MVC3 will route to.
);
That will map and catch the request to the Home/MethodOne action method.

Related

Html.BeginForm with dynamic routevalues

I need to add a dynamic routevalue in html.beginform, something like this
Html.BeginForm("action", "controller", new {
somethingID = "some js function or jquery that get the value from a textbox"
}))
I know mvc is already passing the paramenter to my method when the form submit, but I need the url to include the parameter in the mvc url format, ie mydomain.com/controller/action/somethingID. Eveything is working right now, but because I have another $.ajax() call that pass in the url, something like "../someMethod", the $.ajax() dont work because the current url is (mydomain.com/controller/action) not (mydomain.com/controller/action/somethingID).
Make sure to set as UrlParameter.Optional the id in your RouteConfig:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional}
);

Rendering of #Ajax.ActionLink is messed up by adding a new route

I have an ActionLink:
<td>
#Ajax.ActionLink(item.HostedBy, "_DetailsMerged", "Marcher",
new { id = item.HostedById },
new AjaxOptions
{
UpdateTargetId = "marcherId" + #i ,
HttpMethod="GET",
InsertionMode = InsertionMode.Replace,
})
</td>
that displays the appropriate link when I just have default routing. However, introducing a route for a geolocation proxy, (which implments IRouteHandler and is a custom route handler) BEFORE the default routing:
routes.Add("WebgisUscproxy", new Route("WebgisUscproxy", new OpenLayers_Bronze.Utility.WebgisUscProxyHandler()));
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
while working OK for semi-hard-coded links in my client javascript ajax call (that look like: /WebgisUscproxy?zip=10003), screws up how the #Ajax.ActionLink links are rendered. They ALSO pick up '/WebgisUscproxy'. So I get:
http://localhost:59723/WebgisUscproxy?action=_DetailsMerged&controller=Marcher&id=1
instead of:
http://localhost:59723/Marcher/_DetailsMerged/1
which is what I want, and get with just the default routing. Putting:
routes.Add("WebgisUscproxy", new Route("WebgisUscproxy", new OpenLayers_Bronze.Utility.WebgisUscProxyHandler()));
AFTER the default route handler also doesn't work, as the default routing now matches semi-hard-coded links, like '/WebgisUscproxy?zip=10003'.
==========================================================================
I've found a work-around, though I hope somebody posts something more direct.
routes.MapRoute("webgisusc", "WebgisUscProxy",
new { controller = "Utility", action = "WebgisUsc" }
).RouteHandler = new OpenLayers_Bronze.Utility.WebgisUscProxyHandler();
I had created an empty Utility controller, and was going to add a dummy "WebgisUscProxy"
action to it, but it turns out that there's no need for even a dummy UtilityController. This route definition works, all by itself.

Basic MVC routing query using default project template

I am in the process of learning MVC 3 using the basic project template coupled with several examples I have. Things are going well, but now I am trying to implement my controllers and I am having a couple of issues.
So far I have modified the _Layout.cshtml file to have a new link with a specified route defined:
<header>
<div id="title">
<h1>My MVC Application</h1>
</div>
<div id="logindisplay">
#Html.Partial("_LogOnPartial")
</div>
<nav>
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.RouteLink("Contracts", "Contract")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
</ul>
</nav>
</header>
and my global.asax.cs file is as follows:
routes.MapRoute(
"Contract",
"Contract",
new { controller = "Contract", action = "List", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
This works fine as in it returns the expected action view from my Contract controller.
However I would like to modify this to accept an id into the List action. I know that I need to change the List method to accept a parameter, no problem there, but the issue it with the route and how to pass this paramter into the List method from the RouteLink in the _Layout.cshtml file. I have tried a few things, but this bit is really stumping me.
I intend to pass an id from the User that I logged in as through the AccountController, however I will ask another question about that to keep this more consise.
Thank you very much.
You don't actually need your Contract route, as your Default route will work for any controller and action that corresponds to the pattern controller/action/(optional id parameter here). See the comment in the template actually says Parameter defaults. This means, if there is no Controller, Action, or id passed in, it will default to those values. That's why you can just browse to the root of the website and the Home controller's Index action is the default call.
When using routes, you need to remember that the route parameter names need to match the parameter names in your actions.. for example, your Default route currently lets you do this:
[HttpGet]
public ActionResult MyAction(int id) {
}
But, if you changed your default route to be this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{myIDParameter}", // URL with parameters
new { controller = "Home", action = "Index", myIDParameter = UrlParameter.Optional } // Parameter defaults
);
..your Index action would no longer bind the integer parameter properly.. you would have to change the action to this:
[HttpGet]
public ActionResult MyAction(int myIDParameter) {
}
In answer to your question, it might make more sense to use an ActionLink, like the other two you already have:
#Html.ActionLink("Contracts", "Contract", "ActionMethodHere", new { id = UserIdHere }, null)
That assumes though, that you remove your Contract route and just use the default route.

ASP.NET MVC 3 Controller route - make everything under home controller appear under the domain

Currently everything under homecontroller appears in the URL as
example.com/Home/{Action}
Is there a way we can keep all other routing the way it is but ONLY special case home controller so everything under home comes under the domain.
like
example.com/about
example.com/contact
example.com/error
instead of creating new controller classes for each of them.
EDIT:
The other URL's like
example.com/user/details/123
example.com/user/edit/123
Which are in the userController should work the same as they are now
I think the best way is:
routes.MapRoute("home", "home", new { controller = "Home", action = "Index" });
routes.MapRoute("about", "about", new { controller = "Home", action = "About" });
routes.MapRoute("contact", "contact", new { controller = "Home", action = "Contact" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
and when you want to create a link, use:
#Html.RouteLink("Home", "home", new{/* route values */}, new {/* html attribues */})
OR:
#Html.RouteLink("Home", "home")
instead of:
#Html.ActionLink("Home", "Index", "Home", new{/* route values */}, new {/* html attribues */})
this works for me, and should work for you too.
UPDATE:
you can create a symbol like # (or - or anything else), before the action part in url, to make the url unique, such as:
routes.MapRoute(
"test", // route name
"#{action}", // url and parameters
new {controller = "MyHome", action = "Home"} // parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
in this way, your urls are different from the Default map-route and you can create urls like:
site.com/#Home
site.com/#About
site.com/#Contact
but the first, in my idea, is better and I always use that.
Using the Attribute Routing of MVC5, I did similar to Javad_Amiry answer, by placing a route for each action in HomeController:
public class HomeController : Controller
{
[Route("about")]
public ActionResult About()
{
return View();
}
I think this is more maintainable than placing every action in the global RouteConfig.cs file. Better still to combine Attribute Routing with convention-based routing, so new actions added to controller will work by default without a Route attribute (eg: /Home/action) but can be improved by adding the Route attribute (eg: /action).
You could simply modify the default route and remove the controller bit from the url and specify that it will always be Home in the default values:
routes.MapRoute(
"Default",
"{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Obviously you realize that this limits your application to a single controller which is HomeController as now you no longer have any possibility to set it in your url. Stuffing all the actions in a single controller is a bad practice IMHO and violates a couple of principles like RESTful routing and SRP.
ASP.NET MVC root url’s with generic routing

LogOnPartial renders with a blank href - MVC 3

I'm using a standard MVC 3 Web Project and I've written my HTML out in a standard HTML file, and then copy/pasted it into the _layout.cshtml file. With all the correct RenderBody() and #Html.Partial("_LogOnPartial") included the page works fine, but the ActionLink inside the _LogOnPartial doesn't render an href.
Html.ActionLink("Log On", "LogOn", "Account")
Will come out as:
Log On
This is unchanged from the standard link that you get when you start an MVC 3 Web project.
The registered Routes are:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Products",
"{controller}/{action}/{id}",
new {controller = "Products", action = "Index"});
routes.MapRoute(
"Newsletter",
"{controller}/{action}/{emailAddress}",
new { controller = "Newsletter", action = "Index" });
routes.MapRoute(
"Account",
"{controller}/{action}/{id}",
new { controller = "Account", action = "LogOn", id = UrlParameter.Optional });
}
I don't understand why this is happening, but in Visual Studio it is not underlining the Action or Controller which makes me think it isn't seeing the AccountController properly. Anyone got any ideas?
Fabian is right. The problem is because there are too many routes, many of which are almost identical in their pattern. Your "Default", "Products" and "Account" routes all look for a controller, an action and an optional ID (either explicitly or implicitly). You would probably have considerably more success if you just set the default controller back to its factory-standard form like so:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
}); // Parameter defaults
routes.MapRoute(
"Newsletter",
"{controller}/{action}/{emailAddress}",
new { controller = "Newsletter", action = "Index" });
}
Since the ID is optional, your Products routes will still be matched if you supply an ActionLink with no ID (e.g. #Html.ActionLink("My Link", "Products", "Index")) and the form of the "Account" route is identical to the "Default" one anyway. There's no need to use it and MVC is likely being tripped up between these, which is causing your LogOn partial's Href to fail.
ActionLink doesn't look at the controller or it's actions, just the routing table. Make sure you have a route with action "LogOn" and controller "Account" set in your global.asax.
Edit:
I recommend you read up a bit on mvc routing. Your current routes are too greedy and will match when they shouldn't.
For LogOn i would use something like this (put it at the top because its the least greedy since it doesnt contain any variables):
routes.MapRoute(
"Account",
"logon",
new { controller = "Account", action = "LogOn", id = UrlParameter.Optional });

Resources