So, I am trying to submit a form on a List Page(http://example.com:3480/List) which is actually a Search implementation. So far I have done this:
index.cshtml
#using(Html.BeginForm("Search","ListController"))
{
<input id=query type=text name=query />
<input id=btnsearch type=submit value=Search />
}
ListController.cs
[HttpPost]
public ActionResult Search(FormCollection collection)
{
Response.Write("We are here");
// Get Post Params Here
string var1 = collection["query"];
Response.Write(var1);
return View();
}
Global.asax
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Details",
"Details/{id}/{orderid}",
new { controller = "Details", action = "Index", id = UrlParameter.Optional, orderid = UrlParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults
);
}
Upon Clicking it goes to http://example.com:3480/ListController/Search which seems fine.
Now I guess I need to define route in Global.aspx but not sure. What I want is to show result in same View file instead of creating a new one.
At this moment I am unable to get into Search method after POSTing form
Assuming you are currently just using the default route, the reason you are not reaching the action method is that the "Controller" suffix on your route is implicit - it shouldn't be part of your URL.
#using(Html.BeginForm("Search","List"))
Additionally, regarding:
What I want is to show result in same View file instead of creating a new one.
You can easily return a specific view from any controller action by specifying the name of the view in the call to the View method:
return View("Index");
Related
Edited the question as I've found out that the issue isn't inside the razor, but instead in the route
I have a very simple login form, but somehow, when the user presses Login the page goes tot Error404 and it simply does not hit the controller breakpoints for some reason.
#using (Html.BeginRouteForm("MyCustomRoute", new { controller = "login", action = "verify", FormMethod.Post }))
{
<fieldset class="clearfix">
<p><span style="float:none;color:black; font-size:20pt;"></span></p>
<p><span style="float:none;color:black; font-size:20pt;"></span></p>
<p><span class="fa fa-user"></span>#Html.TextBoxFor(m => m.UserName, new { #class = "form-control", placeholder = "Username", onkeydown = "convertTabtoEnter(this, event)", autofocus = "" })</p> <!-- JS because of IE support; better: placeholder="Username" -->
<p>
<span class="fa fa-lock"></span>#Html.PasswordFor(m => m.Password, new { #class = "form-control", placeholder = "Password", onkeyup = "convertTabtoEnter()" })
</p> <!-- JS because of IE support; better: placeholder="Password" -->
<div>
<span style="width:48%; text-align:left; display: inline-block;">
<a class="small-text" href="#">
#*Forgot
password?*#
</a>
</span>
<span style="width:50%; text-align:right; display: inline-block;"><input type="submit" value="Sign In"></span>
</div>
</fieldset>
<div class="clearfix"></div>
}
And Inside my login controller I have a simple ActionResult named Verify with the 2 params.
[RoutePrefix("Login")]
public class LoginController : Controller
{
// GET: Login
public ActionResult Index()
{
return View();
}
[HttpPost]
[Route("Verify")] //Matches GET login/verify
public ActionResult Verify(string username, string password)
{...}
What exactly am I doing wrong here? It's not like this is rocket science.
Edit2:
I've noticed that whenever I change the RouteConfig.cs back to default it works correctly. So, the problem isn't inside the form tags but within the routings.
So I've been trying to add a custom route in order to get this working using this sample: Using Html.BeginForm() with custom routes
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "TrailersOverview",
url: "{TrailersOverview}/{action}/{vendid}",
defaults: new { controller = "TrailersOverview", action = "Index", vendId = UrlParameter.Optional }
);
routes.MapRoute(
"MyCustomRoute", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "login", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
name: "Default",
url: "{*anything}",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional }
);
}
}
When I remove the routings and I simply bring everything back to default, the controller does get hit. Unfortunately I really need those routings for the rest of the app :(
There are several things that seems to be wrong:
Your Controller is missing in the route Config.
Action and Controller names are in wrong order.
RouteConfig:
A default route looks like that:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}/",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Form:
If you want to use Tag Helpers, then you have to change your code from:
<form action="#Url.Action("Login", "Verify")" method="post">
to:
<form asp-controller="Login" asp-action="Verify" method="post">
Have a look here.
#using (Html.BeginForm("Verify", "YourControllerName", FormMethod.Post))
{ your form here // }
please try this if it works !
One more thing add name attribute in your input fields which should be similar to the property name in your model like
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control", id="username", name="USERNAME"})
And this USERNAME should be there in your model like:
Public class yourModel{Public string USERNAME{get;set;}}
And use your Model Object in your Action Method to fetch data.
Your custom route (the second in your RegisterRoutes code above) seems to be incorrect... based on what you stated above, it can/should be this:
routes.MapRoute(
"MyCustomRoute", // Route name
"Login/Verify", // (No parameters needed)
new { controller = "Login", action = "Verify" } // Parameter defaults
);
With this setup, alter the first line of your razor code to be this:
#using (Html.BeginRouteForm("MyCustomRoute", FormMethod.Post }))
{
<fieldset class="clearfix">
...
}
Using Html.BeginRouteForm will automatically use the defaults specified in your custom route; no need to add the defaults in Razor. Using FormMethod.Post as the second parameter will render your form's method as a POST.
Edit:
Let's fix your general Route problem. You're attempting to use Attribute Routing, which is described well here: https://www.dotnettricks.com/learn/mvc/understanding-attribute-routing-in-aspnet-mvc. I'd contend that it isn't necessary here.
First, fix your default Route (last route in your RegisterRoutes code) like so:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
// Change the 'controller' and 'action' parameters here to point to the Main page in your application.
Your default Route is very important, and should be configured as a catch-all for any requests can be simply mapped to a Controller/Action combination. I suspect that you experienced problems because your default Route was altered.
Next, comment out the Route and RoutePrefix attributes in your Login Controller... there's hardly a need for the [Route("Verify")] directive if you're using 'RegisterRoutes' properly.
// [RoutePrefix("Login")]
public class LoginController : Controller
{
// GET: Login
public ActionResult Index()
{
return View();
}
[HttpPost]
// [Route("Verify")] //Matches GET login/verify
public ActionResult Verify(string username, string password)
{...}
}
Now that the default Route is set up properly, the url '/Login' should take you to your Login screen, because the default action is "Index" (it's the default in your default Route above.)
Try adding routes.LowercaseUrls = true; to your route config as you seem to prefer lower-case versions of routes:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.LowercaseUrls = true;
routes.MapRoute(
name: "TrailersOverview",
url: "{TrailersOverview}/{action}/{vendid}",
defaults: new { controller = "TrailersOverview", action = "Index", vendId = UrlParameter.Optional }
);
routes.MapRoute(
"MyCustomRoute", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "login", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
name: "Default",
url: "{*}",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional }
);
}
}
And for the default route, I think you wanted to mention {*} for url to match everything else?
I suspect someone will call this a duplicate....I have looked through the examples that I have seen and tried to implement the suggested changes but I am still having this issue. In my index view, I have an ActionLink HTML Helper to redirect to an Edit. When I mouse over it, it shows the URL target as:
http://localhost:58028/Instruments/Edit?InstrumentId=1
Instead of the desired
http://localhost:58028/Instruments/Edit/1
I have built a "for comparison" scaffolded situation and it appears to me that I am doing the exact same thing, yet it is resulting in the proper URL. When I debug and stop in the Edit routine of the controller, it shows me that it is using the correct (and only) mapping.
Can someone please tell me what I am missing:
Here's my View code:
<td>#Html.ActionLink(item.Description, "Edit", new { InstrumentId = item.InstrumentId })</td>
Here's my Controller code:
public ActionResult Edit(int? InstrumentId)
and here's my routing:
public static void RegisterRoutes(RouteCollection routes)
{
//routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Your default route expects a parameter named id, so to use the default route, change the link to
#Html.ActionLink(item.Description, "Edit", new { id = item.InstrumentId })
and the method to
public ActionResult Edit(int? id)
or create a specific route for your method that includes a placeholder for a parameter named InstrumentId and place it before the default route
routes.MapRoute(
name: "InstrumentEdit",
url: "Instruments/Edit/InstrumentId",
defaults: new { controller = "Instruments", action = "Edit" }
);
routes.MapRoute(
name: "Default",
....
Both options will generate ../Instruments/Edit/1
try changing the Html Helper to this
#Html.ActionLink(item.Description, "Edit", new { id = item.InstrumentId })
I have a bunch of mostly-static pages (about 40),
like: order-form01.html, order-form02.html, orderform03.html etc..
Should each of them have its own Controller/Action, or is that possible to have one dynamic Controller/Action for all of them?
My Url should look like this: http://MyProject/GlobalController/IndividualView and for the above example: http://MyProject/OrderForm/order-form01, http://MyProject/OrderForm/order-form02 etc..
Thanks in advance.
Yes it's very easy AND you don't need a switch statement or any other redundant logic.
public class MyController
{
public ActionResult Page(string file)
{
return View(file);
}
}
The magic is in the Route Map:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// New MapRoute for your 40+ files..
routes.MapRoute(
"OrdeForm",
"OrderForm/{file}",
new { controller = "MyController", action = "Page", {file} = "" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
Additionally:
I pass the View name in the query string.
Is not required, but is supported. The following urls will work:
// Url Parameters
http://MyProject/OrderForm/order-form01
http://MyProject/OrderForm/order-form02
// Querystring Parameters
http://MyProject/OrderForm?file=order-form01
http://MyProject/OrderForm?file=order-form02
The only catch is that you need to rename your html files to cshtml and place them in the correct directory for the ViewEngine to find.
#Erik, I also bit of new to mvc . Could you please explain your route map as of how is it possible with default raute again and again
Routes are broken down into 3 values:
Controller
Action
Parameter(s)
At a bare minimum, the controller and action are required. Where the values come from is not dependent on the Url. For example, in the following Url and Map Route...
// Url
http://MyProject/
// MapRoute
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = "" }
);
// Controller named "Home" matches the default in the above route
// Method named "Index" matches the default in the above route
public class HomeController {
public ActionResult Index() {
return new EmptyResult();
}
}
... everything still works because we provided a default value for the controller and action.
Ok let's break down the URL you want:
http://MyProject/OrderForm/order-form01
http://MyProject/OrderForm/order-form02
http://MyProject/<identifier>/{parameter}
You have one identifier that tells me route (OrderForm) and one changing value that because it changes and you want one value, should be a parameter.
http://MyProject/<identifier>/{file}
The name of the parameter makes no difference as long as it matches the signature of the controller method:
http://MyProject/{Controller}/{file}
public class HomeController {
public ActionResult Index(string file) {
return new EmptyResult();
}
}
or
http://MyProject/{Controller}/{einstein}
public class HomeController {
public ActionResult Index(string einstein) {
return new EmptyResult();
}
}
I named the parameter file, because it tells me it's the parameter is a name of a file, whereas the name einstein has no inherent description so is a terrible name for a variable.
http://MyProject/{Controller}/{file}
// MapRoute
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = "" }
);
// Controller named "Home" matches the default in the above route
// Method named "Index" matches the default in the above route
public class HomeController {
public ActionResult Index() {
return new EmptyResult();
}
}
Now we only want this route to run when the identifier is OrderForm so we don't allow that to be a value, we hard code it.
url: "OrderForm/...
Next we have a value that keeps changing, so we to add url parameter:
url: "OrderForm/{file}"
Now we have an issue because we aren't allowing MVC to parse values from the url to populate Controller nor Action so we must supply them.
routes.MapRoute(
name: "",
url: "OrderForm/{file}",
defaults: new { controller = "Home", action = "Index", file = "" }
);
Here we've mapped the url http://MyProject/OrderForm/{file} to:
public class HomeController {
public ActionResult Index(string file) {
return new EmptyResult();
}
}
Now I would choose to to update the defaults to something more specific and descriptive:
routes.MapRoute(
name: "",
url: "OrderForm/{file}",
defaults: new { controller = "OrderForm", action = "Index", file = "" }
);
public class OrderFormController {
public ActionResult Index(string file) {
return new EmptyResult();
}
}
Hope that all makes sense.
After the question edited :my solution is, you can have one controller/action and it should call view (cshtml). Your querystring data should be pass to view as of viewbag variable and partial views should be called acording to the viewbag variable. noo need of editing routing table even(if you are willing to pass it as a query string).
//your routeconfig will be
routes.MapRoute(
name: "default",
url: "{controller}/{file}",
defaults: new { controller = "OrderForm", action = "Index", file = "" }
);
//here no need to have 40 routing table one is enough
//your controller/action will be
public class OrderForm
{
public ActionResult Index(string file)
{
ViewBag.Orderform=file
return View(file);
}
}
//view bag variable is accessible in view as well as in javascript
But I would say as best practice, you can modify default routing to access all urls and navigate it to same controller/action and let that action to return the view. After that use angular / knockout js to handle client side routing and based on it the partial views should be loaded.(still your url will be different for your 40 pages but noo need to pass it as query string)
//your route table will be
routes.MapRoute(
name: "default",
url: "{controller}/{file}",
defaults: new { controller = "OrderForm", action = "Index"}
);
//your controller will be
public class OrderForm
{
public ActionResult Index()
{
return View(file);
}
Navigation should be handled by client side routing
I was referencing this question to try and get this done, but it only works for my index method and I am not sure why.
My project has one area in it (if that is relevent) and I have about 5 different views that I want to hide /home/ in the url.
Code:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"JobResults", // Route name
"JobSearch/{title}-{id}", // URL with parameters
new { controller = "JobSearch", action = "Job" }, // Parameter defaults
new[] { "inkScroll.Web.Controllers" }
);
routes.MapRoute("home", "{action}",
new { controller = "Home", action = "index" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new
{
controller = "^(account|common|base|jobsearch)$", //every controller goes in here
action = "Index",
id = UrlParameter.Optional
},
new[] { "inkScroll.Web.Controllers" }
);
I am solving the same problem with the help of Attribute based Routing feature of ASP.NET MVC 5. Say, I have an action named ContactUs in my Home Controller as follows:
public ActionResult ContactUs()
{
return View();
}
I used to get Url for ContactUs as /Home/ContactUs. But, I wanted it to be simply /ContactUs. So, I am decorting the ContactUs action with Route Attribute as follows:
[Route("ContactUs")]
public ActionResult ContactUs()
{
}
So, this is working perfectly for me. Therefore, if you are using ASP.NET MVC 5, I would say, utilize this excellent feature of MVC5. It will not only save you from separating Route Logic and Actions, but also, it solves many problems very easily.
If ASP.NET MVC5 is not an option for you, or if you dont want to use Route Attribute on Action Methods, then, perhaps the following route can work: ( I did not test it though)
routes.MapRoute("Default", "",
new { controller = "Home", action = "index" });
This page contains helpful resource about Attribute Routing: http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
Catch all wildcard route as the last one would work
routes.MapRoute("home2", "{*path}",
new { controller = "Home", action = "index" });
I having some problems overloading the Index action in a controller. In the controller I have the following actions:
public ActionResult Index(int id)
{
return View();
}
public ActionResult Index()
{
return View();
}
Going to either URL (controllername/ or controllername/1) results in a 500 error. However when I use:
public ActionResult Index(int? id)
{
return View();
}
The controllername/ URL works but controllername/1 results in a 404 error. My global.asax is pretty vanilla:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
What I would like to do is be able to handle a null id as well as an integer id value. Any suggestions would be greatly appreciated.
Thanks!
I think you will need to explicit the routes for that:
routes.MapRoute(
"ControllerName", // Route name
"ControllerName/{id}", // URL with parameters
new { controller = "ControllerName", action = "Index", id = UrlParameter.Optional }
);
if it doesn't work, you may need to be more explicit and add this before:
routes.MapRoute(
"ControllerName",
"ControllerName",
new { controller = "ControllerName", action = "Index"}
);
I think you don't need an overload here, but just need a check inside the index action for the null.
Overloading action is not a good idea, because framework would have no idea of which action to call incase of null index.
Adding custom routing for every action overload will cause slower response time because of too many custom routes to resolved.