The application manages requests. There is a ActionLink that should pass in the id of a request so it can be reset. The correct controller/action is called, but the request ID is always null.
If I change the last parameter of the custom route (shown below) to id="TEST", then "TEST" gets passed into the function - so I know the correct route is selected.
In controller BrowseController.cs
[HttpGet]
public ActionResult ResetRequest(string id )
{
return View();
}
In View BrowseRequests.cshtml there is a link to reset a request
#Html.ActionLink(
"Reset",
"ResetRequest",
"Browse",
new {id = item.RS_RequestID.ToString() });
I've tried the default routing in RouteConfig.cs, and then tried inserting the following before the default.
routes.MapRoute(
name:"ResetRequest",
url:"Browse/ResetRequest/{id}",
defaults: new { controller = "Browse",
action = "ResetRequest",
id=UrlParameter.Optional});
The correct overload for your ActionLink would be
HtmlHelper.ActionLink(string linkText,string actionName,string ControllerName, object routeValues, object htmlAttributes);
so you are missing object htmlAttributes which you can pass as null
#Html.ActionLink("Reset","ResetRequest","Browse", new {id = item.RS_RequestID.ToString() }, null);
The order of the values you pass into ActionLink is not correct
use action, controller, routevalues , htmlArguments
Your first argument should be ResetRequest
Your suggestion resulted in a "resource not found" error. It did get me thinking that perhaps I was using the incorrect signature for the ActionLink.
I found an override that did not specify the controller - just the action.
This is what worked for my purposes
#Html.ActionLink(
"Reset",
"ResetRequest",
new { id = item.RS_RequestID.ToString() });
Related
I have a asp.net mvc form and i want to submit it to same page via get method, it's used for search purpose.
The url is mapped with route key value id.
#using (#Html.BeginForm("Contact", "Home",FormMethod.Get))
{
#Html.TextBox("id", null,
new
{
type = "time"
}
);
<input type="submit" />
}
When the form is generated the action attribute is containing the key value like /Home/Contact/myname.
Here myname is value of id present in url.
When form is submitted value key value for id is getting appended to URL like
http://localhost:57247/Home/Contact/myname?id=11%3A11
The action method is reading myname value instead of 11%3A11.
Action Method:
public ActionResult Contact(string id)
{
ViewBag.Message = id;
return View();
}
It's working fine with post method.
How to fix this?
replace #Html.BeginForm("Contact", "Home",FormMethod.Get)
with #Html.BeginForm()
By default forms are sent to same url they are rendered on and default method is get.
#Html.BeginForm() by default produces a METHOD="POST"
As for your parameter you might want to name it differently.
Default Mvc route is configured like this
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Depending on mvc version it can be in global.asax or App_Start\routeconfig.cs
So your "MyName" in url perfectly matches default id parameter and it has higher priority than query string parameters.
If you name your parameter differently (not id).
Change it to "q" for example in action and in view.
Your URLs will change to /Home/Contact?q=myname and everything should start working as expected.
Now you say that you want a solution with url mapping.
So you have to figure out for yourself what url scheme you want.
If you have a form and want it to post to /home/contact/myname?id=notyourname, than you have a conflict which to solve you will have to somehow change binding priorities in mvc.
Now you can inspect querystring on your own in your action and figure out new id passed without binding. After that you can return RedirectToAction("Contact", new{id = figuredId}) and the url in browser will be what you want it to be.
You can change the query parameter name and have your action recieve 2 parameters
public ActionResult Contact(string id, string q){
if (!string.IsNullOrWhitespace(q)){
return RedirectToAction("Contact",new{id=q});
}
}
To send request to /Home/Contact you should use #Html.BeginForm("Contact","Home",new{id=null}, FormMethod.Get)
Using bootstrap I ran into the problem of having to set the active class on certain links. I found this helper method out on the interwebs and was adding some functionality to it. Basically I wanted to add RouteValueDictionary and Html items to it. For some reason, my view is passing a null RouteValueDictionary instead of the values I'm populating.
I think my problem is I am missing something on the view side, the HTML rendered might not actually produce a route value the way it should.
Extension method:
public static MvcHtmlString MenuLink(this HtmlHelper pHtmlHelper, string pLinkText, string pActionName, string pControllerName, RouteValueDictionary pRouteValues)
{
var vCurrentAction = pHtmlHelper.ViewContext.RouteData.GetRequiredString("action");
var vCurrentController = pHtmlHelper.ViewContext.RouteData.GetRequiredString("controller");
var vBuilder = new TagBuilder("li") { InnerHtml = pHtmlHelper.ActionLink(pLinkText, pActionName, pControllerName, pRouteValues, null).ToHtmlString() };
if (pControllerName == vCurrentController && pActionName == vCurrentAction) vBuilder.AddCssClass("active");
return new MvcHtmlString(vBuilder.ToString());
}
View (portion):
#Html.MenuLink("Account", "Details", "Dashboard", new RouteValueDictionary(new {id="Account"}))
Rendered HTML:
Account
So again, the problem I'm having is MenuLink gets a null RouteValueDictionary, I feel like it should contain id!
(Note... pHtmlHelper.ViewContext.RouteData actually contains the id tag in it's RouteData Values....)
Your code is working as expected assuming you have a route that looks like (depending on the order of the routes):
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters*
new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
So the code:
pHtmlHelper.ActionLink(
pLinkText, // Link Text
pActionName, // Action
pControllerName, // Controller
pRouteValues, // Route Values
null)
.ToHtmlString() };
The Url would be
/Dashboard/Details/{id}
Route Values:
{
id="Account"
}
becomes:
/Dashboard/Details/Account
I'm asking how to do a link with #Url.Action in a Razor view to make a link like
Controller/Action/123
I already made #Url.Action("Action","Controller", new { #ViewBag.ID }) but it makes me a link like
Controller/Action?ID=123
How do I make a URL without the querystring in the razor view?
Try:
#Url.Action("actionname", "controllername", new { id = ViewBag.Id})
I think the problem is just that you haven't specified that the value in your route parameters collection is the "id". Of course, I'm assuming that you're using the default route configuration in RegisterRoutes.
Tip: you can also use Html.ActionLink() which saves you the trouble of creating an <a> tag yourself:
#Html.ActionLink("linkText", "actionName", "controllerName", new { id = ViewBag.ID }, null);
This will generate an <a> tag with the linkText and the same url as Url.Action() which you can see in Jeff's answer.
Note: don't forget to add null as the last parameter, otherwise it will use the wrong overload and use the anonymous type as htmlAttributes.
Use Url.RouteUrl(String, Object) and notUrl.Action()
Use the default route name.. which must be Default
so your code should be :
#Url.RouteUrl("Default", new {controller = "SomeControler", action = "SomeAction" , id = #ViewBag.ID })
Doing that will give you url as follows : SomeController/SomeAction/5 (assuming ID was 5)
This happens because of the by default the project mvc template contains a Default route as follows :
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You can create more fancy urls if you wish or if you need more parameters, by adding more routes into routing table
here's the description : http://msdn.microsoft.com/en-us/library/dd505215(v=vs.108).aspx
#Url.Action("Action/" + #ViewBag.ID,"Controller")
I am using Martijn Bolands paging and I have an issue with GetVirtualPathForArea method.
I have two pages: /Page1 and /Page2.
I've set a MapRoute for /Page1 and is accessed as /Page1Name
routes.MapRoute(
"Page1 name", // Route name
"Page1Name", // URL with parameters
new { controller = "ContollerName", action = "ActionName" } // Parameter defaults
);
If I try to get the Vitrual Path from Page1Name page, it gives me the correct one.
But!! If I try to get the Virtual Path from page2, it gives me again the Page1Name.
I haven't set any Route for Page2 and If do this, then in Page1 I will get the VirtualPath of Page2.
Call and Methods
The call is through an HtmlHelper as follows
public static HtmlString Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, string actionName, RouteValueDictionary valuesDictionary, string controllerName) {
if (valuesDictionary == null) {
valuesDictionary = new RouteValueDictionary();
}
if (actionName != null) {
if (valuesDictionary.ContainsKey("action")) {
throw new ArgumentException("The valuesDictionary already contains an action.", "actionName");
}
valuesDictionary.Add("action", actionName);
}
var pager = new Pager(htmlHelper.ViewContext, pageSize, currentPage, totalItemCount, valuesDictionary, null, controllerName);
return pager.RenderHtml();
}
This is from RenderHtml() method
It gets the viewContext from htmlHelper and this is the call to get the virtualPath
var pageLinkValueDictionary = new RouteValueDictionary(linkWithoutPageValuesDictionary) { { "page", pageNumber } };
var virtualPathForArea = RouteTable.Routes.GetVirtualPathForArea(viewContext.RequestContext, pageLinkValueDictionary);
Is it a known issue? Have I set something in a wrong way?
Thanks and I'll appreciate any comment.
Response from microsoft:
The behavior you’re mentioning here is actually “by design”, if a route URL (such as your first route: FirstPage) has no parameters, no defaults, and no constraints, the call to RouteTable.Routes.GetVirtualPathForArea() will match this route (when it gets to it as it tries to match the route one by one in the order they are added).
The general fix is to make one of those conditions false OR to use named routes.
You can read more about this in a blog post by Phil Haack here: http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx
Normally, a route that is registered could look like
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "ControllerName", action = "ActionName", id = UrlParameter.Optional } // Parameter defaults,
);
meaning that doing a Url.Action("Index","Home", new {id = 1}) would result in the url /Home/Index/1; the {controller}/{action}/{id} are placeholders for both interpreting a request (which controller, action and parameters to use) and generating url's.
If you look at your route defined (if it is the only one, or defined as the first) whatever you do with a Url.Action(..) it will always return /Page1Name
If you want to do as in the link provided
Internally, the pager uses RouteTable.Routes.GetVirtualPath() to render the url’s so the page url’s can be configured via routing to create nice looking url’s like for example /Categories/Shoes/Page/1 instead of /Paging/ViewByCategory?name=Shoes&page=1.
Then you can register your route like:
routes.MapRoute(
"PagingRoute", // Route name
"Categories/{type}/Page/{page}", // URL with parameters
new { controller = "PagingControllerName",
action = "Index",
type = UrlParameter.Optional,
page = UrlParameter.Optional } // Parameter defaults,
);
and the matching method in the PagingController would be
public ActionResult Index(string type, int? page) { // do something}
update
If you are using Martijn Bolands pager, look at the second route he maps/registers:
routes.MapRoute("SimplePaging", "SimplePaging/{page}",
new { controller = "Paging", action = "Index", page = UrlParameter.Optional },
new[] { "MvcPaging.Demo.Controllers" });
then yours should be about the same (i.e. adding the UrlParameter page). But that would mean your url will always look like /Page1Name/[pagenumber]. If on the other hand Page1Name is your actual action, you should define your Route like:
routes.MapRoute("Page1 name", "{action}/{page}",
new { controller = "Paging", action = "Page1Name", page = UrlParameter.Optional },
);
I've got the default routing:
routes.MapRoute(
"Shortie", // Route name
"{controller}/{id}", // URL with parameters
new { controller = "Ettan", action = "Index", id = "id" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Ettan", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
I've got a controller: NewsController. It has one method, like this:
public ActionResult Index(int id)
{
...
}
If I browse to /News/Index/123, it works. /News/123 works. However, /News/Index?id=123 does not (it can't find any method named "index" where id is allowed to be null). So I seem to be lacking some understanding on how the routing and modelbinder works together.
The reason for asking is that I want to have a dropdown with different news sources, with parameter "id". So I can select one news source (for instance "sport", id = 123) and it should be routed to my index method. But I can't seem to get that to work.
The ASP.NET MVC Routing works using reflection. It will look inside the controller for a method matching the pattern you are defining in your routes. If it can't find one...well you've seen what happens.
So the answer is (as posted in the comments) to change the type of your id parameter to a Nullable<int> i.e. int?.