I have a asp.net MVC website, and I have this url:
Home/Index/
There is one action that I want to do, and currently I'm doing it using query string, like this:
Home/Index/?action=1
I'll then get it in my code using Request.QueryString["action"].
But this does not look as good as it should, I'd like to have something like this:
Home/Index/Action
So the query string would be a third parameter. How can I use it like this and check if the third parameter exists, and it's name?
My routes are configured like this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Do I need to change anything on the routes or I can just enter the way I want, and if so, how do I retrieve this value?
Edit :
Alright. What I wanted to do was to have a different result in the view depending on this parameter.
What I did now was create two ActionResults that use the same View sending different values to the ViewData.
In MVC there is the concept of Model Binding, where the names of the parameters are used and then filled with values from the Form, without you having to do it.
If you write your Action method like this:
public ActionResult Index(int action)
{ ... }
then it will already work for /Home/Index?action=1.
If you want to be able to call it like /Home/Index/1 then the easiest way is to simply write the Action method like this:
public ActionResult Index(int id)
{ ... }
This works because the MapRoute definition basically says 'if there is something after the {action} part (which in this case is "Index", by the way), then give it the parameter name {id} and bind it to the {id} parameter of my Action method".
Update:
The problem with using a parameter called action in both calling scenarios is that {action} is a special keyword in MVC.
To use MySpecialParam for both calling scenarios, you could just add this Route:
routes.MapRoute(
name: "Default_MySpecialParam",
url: "{controller}/{action}/{MySpecialParam}",
defaults: new { controller = "Home", action = "Index", MySpecialParam = UrlParameter.Optional }
);
However if MySpecialParam were to become action, then there is a name resolution conflict that MVC probably won't know how to handle, or it may even throw an error.
The action is supposed to be right after the controller, usually. I think in your case it might be better to add a new controller, which has the action you want.
I gave up mapping routes as this is cumbersome. You need to add a new route for every number of parameters, like follows:
routes.MapRoute(
"ThreeIds", // Route name
"{controller}/{action}/{firstId}/{secondId}/{thirdId}" // URL with parameters
);
routes.MapRoute(
"Dates", // Route name
"{controller}/{action}/{startDate}/{endDate}" // URL with parameters
);
Try doing ajax calls using something like jQuery instead. No nead to add a route for every possibility.
$.ajax({
url: '../' + controller + '/' + method,
data: jsonObjectString,
contentType: 'application/json',
dataType: 'json',
success: function (data) {
//do something
},
error: function (err) {
//do something
}
});
You can use my library at https://github.com/Biot-Savart/MVC-DataCall.js to make life a bit easier.
Related
I've implemented code to encrypt my query string parameter names and values. The code i have implemented will only encrypt query string that contain ?. (This is to prevent encryption of unneeded URL's, such as the .css files).
A way to combat this would be to always show the ? in query strings when only the ID parameter is passed.
For example I would like: http://domain/controller/Action/17
To show as: http://domain/controller/Action/?id=17
I understand that I probably need to edit my routes, I've tried adding the ? symbol to the route which throws the error : The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character.
My routes are defined as:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("favicon.ico");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Login", id = UrlParameter.Optional } // Parameter defaults
);
How can I get my query strings to show like the example given above?
Don't define your parameters in routes.
ASP.NET automaticaly will add the question mark.
You can then call http://domain/controller/Action?id=17 and it will route to
public ActionResult Action(int id) { }
Update: If you want to kill domain/controller/action/id format completely, you need to define the route as:
routes.MapRoute(
name: "Parameterless", //or any name
url: "YourController",
defaults: new { controller = "YourController", action = "YourAction" }
);
Now you can use domain/controller/action?id={id} and domain/controller/action/id will 404.
If you are getting a Server Application Error, you need to provide more details, since it might be related to something else.
Mvc 5, .Net 4.5
I implement MvcSiteMapNodeAttribute as follows:
[MvcSiteMapNode(Title="Running Events", ParentKey="Events", Key="RunningEvents")]
public ActionResult RunningEvents()
{
return View();
}
I need to access this page from multiple locations and keep the breadcrumbs in tack (i.e. from the correct calling method). However the ParentKey dictates where the call comes from and thus set the ParentNode based on it. This is not ideal as I want the calling ActionResult to be the parent and not "hard coded" as with the ParentKey solution. The ParentKey is also not editable at runtime nor the ParentNode. The only way around this at the moment is to duplicate the ActionResult with different signatures and give it the same Title which is also not ideal.
I've read up on mvc routing, DynamicNodeProvider, route mapping, etc but cannot find a way to make this work? I'm also not very familiar with mvc so would appreciate some guidance.
Thanks
See the Multiple Navigation Paths to a Single Page documentation.
You can use the same controller action in multiple places. However, you must always provide a unique set of route values (which usually means each URL should be unique).
The most natural way to do this is to design your URLs with the parent category.
routes.MapRoute(
name: "Category1RunningEvents",
url: "Category1/RunningEvents",
defaults: new { controller = "Events", action = "RunningEvents", category="Category1" }
);
routes.MapRoute(
name: "Category2RunningEvents",
url: "Category2/RunningEvents",
defaults: new { controller = "Events", action = "RunningEvents", category="Category2" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And then differentiate the route matching by the category field. You can use multiple MvcSiteMapNode attributes on the same action, each with different parent key in the SiteMap.
[MvcSiteMapNode(Title="Category 1 Events", ParentKey="Events", Key="RunningEvents", Attributes = #"{ ""category"": ""Category1"" }")]
[MvcSiteMapNode(Title="Category 2 Events", ParentKey="Category2", Key="Category2RunningEvents", Attributes = #"{ ""category"": ""Category2"" }")]
public ActionResult RunningEvents()
{
return View();
}
Of course, this isn't the only way to configure the routing but it should clear up the concept. The only limitation is that you must use a unique set of route values for the match, each which corresponds to a node. However, there can be multiple nodes that represent the same controller action, each with a different parent node.
Also see this answer.
I have an app that is just one controller and one action, but I want to pass two values into that action. The end result that I'm looking for is a url that looks like this http://www.example.com/parameter1/parameter2
So I was thinking that the routing would look like this
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}/{name}",
defaults: new { controller = "Home", action = "Index"}
);
and the controller would look like this
public class HomeController : Controller
{
public ActionResult Index(string id, string name)
{
return View();
}
}
But I'm clearly wrong as it doesn't work. Does anyone know if it's possible under the index action?
Just to clarify, I want 2 parameters in the default action. I'm aware it's possible by having something like http://www.example.com/books/parameter1/parameter2/ but I specifically want http://www.example.com/parameter1/parameter2/
To totally omit the controller and action placeholders in the route you can just remove them.
(Do not remove it from your default route, better create a new one and place it about the default one)
routes.MapRoute(
name: "Default",
url: "{id}/{name}",
defaults: new { controller = "Home", action = "Index"}
);
This route will only work with Index action from HomeController but not with others.
If id is optional, what your URL would look like when it's not entered, but name is?
/Home/Index//name
That's obviously invalid.
Consider using the values in the query string instead of part of the URL.
I used this and this to solve the problem.
Need two Routes and make sure these routes come above the default MVC route:
routes.MapRoute(
name: "with-name",
url: "Home/{action}/{id}/{name}",
defaults: new { controller = "Home", action = "Index"}
//No Optional
);
routes.MapRoute(
name: "without-name",
url: "Home/{action}/{id}",
defaults: new { controller = "Home", action = "Index"}
);
I have the following jQuery call in the razor view.
$.getJSON('/Controller/ActionName/'+ #ViewContext.RouteData.Values["Name"] + '?Date=' + ('#StartDate').val(), function (data) {
alert(data);
});
The error in chrome browser console is that the below URL has returned no page found.
http://localhost:{portNumber}/Controller/ActionName/John?Date=9/21/2014&_=1413867422739
it is true because of the added extra token to the end of the url.
Can any one please let me know the reasons for the extra token?
I have an appropriate method in the controller and not able to figure out a solution.
The routeConfig.cs file is not changed and it has the default values to it.
Please let me know in comments if you need further information. I am not able to understand which information to furnish.
Route information:
{
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", name = UrlParameter.Optional }
);
}
Action Signature in the controller
public JsonResult ActionName(string**?** name, DateTime startDate)
{
var model = new ViewModel();
model.loadItems(name**.value**, startDate);
return Json(model.Data, **JsonRequestBehavior.AllowGet**);
}
Answer:
Made the above changes in surrounded by ** and the code worked.
Thank you for the comments and answers.
Update:
I have mentioned the default values in order to hide the unrequired information.
localhost is correct and other pages are working fine just a small part of ui which is related to this ajax call is not working.
No controller is name something else.
Can you please provide a solution for sending date values in URLS?
Change you call to (assuming your controller is really named ControllerController
$.getJSON('/Controller/ActionName/', { name: #ViewContext.RouteData.Values["Name"], startDate: $('#StartDate').val(), function (data) {..
You have a few problems here. Your default route accepts a parameter named ID but your method only has parameters name and startDate. You are not passing any parameters with those names (you are passing one for date but that does not match the method signature parameter)
Note you should not hard code the controller and action names this way. The recommend ways is
var url = '#Url.Action("ActionName", "Controller")';
var StartDate= ('#StartDate').val();
var url="/Controller/ActionName/'+ #ViewContext.RouteData.Values["Name"] + '/";
$.ajax({
url: url,
data: { Date: StartDate},
cache: false,
type: "POST",
success: function (data){
},
error: function (data){
}
});
I've created a system in MVC using the NerdDinner tutorial as a base to work off.
Everything was working fine until I used single action methods such as
Here is the global.asax.cs
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "mysample", id=UrlParameter.Optional }
);
which routes to
http:localhost/Home/mysample
i just want to create routes which has more than one action in the sense
http:localhost/<controller>/<action>/<params>
ex: localhost/mycontroller/myaction/details/myname
Any help much appreciated.
Thanks.
update 1:
i have writen router like this as
routes.MapRoute(
"myname", // Route name
"{controller}/{action}/{details}/{myname}", // URL with parameters
new { controller = "mycontroller", action = "myaction", details= "details", myname= "" } // Parameter defaults
);
and retried the value with following syntax as
String name=RouteData.Values["myname"].ToString();
it works fine .
but even though the url called as
localhost/mycontroller/myaction/details
its being routed to that controller and error is being thrown as null reference...
how to avoid it?
You can't define multiple actions in one MVC route.
In MVC routing configuration is used for mapping your Controlers and Actions to user friendly routes and:
Keep URLs clean
Keep URLs discoverable by end-users
Avoid Database IDs in URL
Understanding default route config:
routes.MapRoute(
name: "Default", // Route name
routeTemplate: "{controller}/{action}/{id}", // URL with parameters
defaults: new { controller = "Home", action = "mysample", id=UrlParameter.Optional }
);
The "routeTemplate" property on the Route class defines the Url
matching rule that should be used to evaluate if a route rule applies
to a particular incoming request.
The "defaults" property on the Route class defines a dictionary of
default values to use in the event that the incoming URL doesn't
include one of the parameter values specified.
Default route will map all requests, because it has defined default values for every property in routeTemplate, {} means that property is variable, if you not provide value for that param in URL, it will try to take default value if you provide it. In default route it has defined defaults for controller, action and id param is optional. That means if you have route like this:
.../Account/Login
It will take you to Account controller, Login action and because you didn't specified prop and it is defined as optional it will work.
.../Home
This will also work, and it will take you to Home contoller and mysample action
When you define custom route, like you did:
routes.MapRoute(
"myname", // Route name
"{controller}/{action}/{details}/{myname}", // URL with parameters
new { controller = "mycontroller", action = "myaction", details= "details", myname= "" } // Parameter defaults
);
You didn't specified myname as optional and you didn't specified it your route, that means that your URL: localhost/mycontroller/myaction/details wan't be handled by your custom route myname. It will be handled by default route. And when you try to access your myname param in controller it wan't be there and you will get null reference error. If you want to specifie default value of your parameter if not present in url you need to do that in your controller. For example:
public class MyController : Controller
{
public ActionResult MyAction(string details = "details", string myname = "")
{
...
and change your custom route to:
routes.MapRoute(
"myname", // Route name
"{controller}/{action}/{details}/{myname}", // URL with parameters
new { controller = "mycontroller", action = "myaction", details= UrlParameter.Optional, myname= UrlParameter.Optional } // Parameter defaults
);
But you can define only one controller and only one action, rest of the routeTemplate are parameters.
You can't define two action in one route. It make no sense.