ActionLink not working as expected - asp.net-mvc

I'm passing empid and I want it to be shown in url but it shows like querystring:
<li>#Html.ActionLink(key.Value, "Attendance","HOD", new {empid=key.Key}, null)
</li>
The link I want to display is like:
/HOD/Attendance/xyz%2Fabc
but it shows me like this:
/HOD/Attendance?empid=xyz%2Fabc //it's like query string but i don't want that.
Can somebody please help? I appreciate any little help. Thanks a lot in advance.
I've this RouteMap added to Global.asax
routes.MapRoute (
"HOD_AttByEmpID", // Route name
"{controller}/{action}/{empid}", // URL with parameters
new { controller = "Account", action = "LogOn",
empid = UrlParameter.Optional }
);

Did you tried like this?
#Html.ActionLink(key.Value, "Attendance","HOD", new { key.Key},null)
Source : HTML.ActionLink method

I guess that is because your value contains a '/'
Maybe you can try :
<li>#Html.ActionLink(key.Value, "Attendance","HOD",
new {empid=Server.UrlEncode(key.Key)}, null)
</li>

Related

MVC Action link with dynamic parameters

I am using MVC and my requirement is that i need to build a action link with dynamic action route value.
for example.
In my model i have the list<string> so action link should be.
../ActionMethodName/ControllerName? Item[0]=model.item[0]&Item[1]=model.Item[1]...so on.
Any Suggestion is welcome.
Several ways.
1) You can pass as array and access it.
3) You can use foreach with razor syntex to generate this type of link.
Initally , the parameter needs to be passed are hardcoded than OnClick of somthing , replace the queryString values .
#Ajax.ActionLink("Test", "actionName", "ControllerName", new { foo = "foo1", name = "ABC" }, new AjaxOptions { UpdateTargetId = "TargetName" }, new { id = "Test" })
and
$("#btnTest").click(function () {
// Replace the hardcoded parameter value desired one ... :)
$("#Test").attr('href', $("#Test").attr('href').replace("foo1", "XXX"))
});
Note:- this solution i read from asp.net forums
http://forums.asp.net/t/1841591.aspx?+pass+Javascript+value+parameter+with+Ajax+ActionLink

I'm not getting friendly url in a form with GET method

I setup a route like that:
routes.MapRoute(
name: "Pesquisar",
url: "Pesquisar/{aaa}/{bbb}/{id}",
defaults: new { controller = "Home", action = "Pesquisar",
aaa = UrlParameter.Optional,
bbb = UrlParameter.Optional,
id = UrlParameter.Optional
}
);
When I press Send button in a form (with GET method) the url is like that:
http://localhost:00000/Pesquisar?aaa=One&bbb=Two
But I was expecting for:
http://localhost:00000/Pesquisar/One/Two
When you map a rout, it adds it to the end of a list. When the router looks for the rule to match, it starts at the begining of the list and itterates through it. It will take the first rule that matches, not the most specific rule. Because it is natural to append code to the end, the default rule (which works for almost everything) will be at the start.
Try re-ordering your code to look like this:
///The specific rout which you want to use
routes.MapRoute(
name: "Pesquisar",
url: "{action}/{aaa}/{bbb}/{id}",
defaults: new { controller = "Home", action = "Pesquisar",
aaa = UrlParameter.Optional,
bbb = UrlParameter.Optional,
id = UrlParameter.Optional
}
);
///The generic catch all router
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
More information can be found in this question:
Setting up ASP.Net MVC 4 Routing with custom segment variables
When I press Send button in a form (with GET method) the url is like that:
http://mydomain.com/Pesquisar?aaa=One&bbb=Two
But I was expecting for:
http://mydomain.com/One/Two
This is because the browser is unaware of the fancy url you want, as the standard form Get method is to append form values in the querystring.
What you mostly likely have to do is something like Creating Canonical URLs including an id and title slug, except redirect to the url you want if it's not the url you want to display.
Or you can use jQuery to manually create the url you want on submit, but requires more client side work.
Not sure if you get a clean URL directly from a html form GET.
One suggestion would be to POST it to an action, do what you need to do with the data, then on completion, redirect to your clean URL.
e.g.
ViewModel:
public sealed class PesquisarModel
{
public string aaa { get; set; }
public string bbb { get; set; }
public string id { get; set; }
}
Controller Actions:
[HttpGet]
public ActionResult Pesquisar(PesquisarModel m)
{
return View();
}
[HttpPost]
[ActionName("Pesquisar")]
public ActionResult PesquisarPost(PesquisarModel m)
{
//do stuff
return RedirectPermanent("/pesquisar/" + m.aaa + "/" + m.bbb + "/" + m.id);
}
View:
#model MyApplication.Models.PesquisarModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.aaa)
#Html.TextBoxFor(m => m.bbb)
#Html.TextBoxFor(m => m.id)
<button type="submit">Submit</button>
}
This is the browser behavior. When making a GET request browser appends all KeyValue pairs to querystring.
The mentioned route format will be available, when we use Html.ActionLink or Html.RouteUrl etc.
You could probably write few code in OnActionExecuting ( or you can use any handler) to reconstruct RouteData and redirect with appropriate url. Below code is not tested
var queries = this.Request.QueryString;
foreach(var query in queries)
{
// Add/Update to RequestContext.RouteData
}
var redirectUrl = Url.RouteUrl("Pesquisar",this.RequestContext.RouteData);
Response.Redirect(redirectUrl);
That's expected behavior.
The routing system is on server side. The browser knows nothing about routes, and what you're doing happens in the browser.
If you want to get that route you have to compose it on the client side with a custom script which uses the <form>'s action, an the values of the <input type="text"> values.
You cannot generate the Url on the server side (which could be done with some UrlHelper extension methods) because the changes on the text boxes wouldn't be updated.
This is not advisable because if you make changes on the routes, you could forget to update them in your browser scripts, breaking you application.
You could avoid this problem by creating the url in the server side using an UrlHelper extension method with special placeholders, which could be easily replaced on the client side. I.e. generate an url like this:
http://localhost/Pesquisar/$aaa$/$bbb$/$id$
by providing RouteValues like this: new {aaa="$aaa$, bbb="$bbb$, id="$id$"} to an UrlHelper method. This url can be stored in the value property of a hidden field.
Then, make a browser script for the click event of your button, recover the url with the placeholders from the hidden field, and replace the placeholders with the actual values of the textboxes. To execute the get run this: document.location = theUrl;
If you want to d this for many differnt instances you could create a Helper to geenrate the hidden field with the Url, and a javascript which makes the replacements.
The question is... is it worth the effort?

Mvc: pass id but not show it in friendly url

I have a view that renders a list of news, in that i have an href tag, and i need to call a Detail method and pass it the news id, now i have a querystring in my url like that
News/Details?id=x... but i need something like News/Details/Category/Title-of-something, a friendly url with news category, name and without the id
this is my action, it works but i get that querystring
foreach (var item in Model)
{
Read More
}
I was trying with something like, with a Url.RouteUrl
routes.MapRoute(
name: "Details",
url: "{controller}/{action}/{id}/{category}/{newsName}",
defaults: new { controller = "News", action = "Details"}
);
but it never goes to Details actionresult, and also i need to pass the id parameter for showing some news Details, but i don't want to display it in the friendly url. Im really confused how to achieve it. Thanks in advance
Try this:
#Html.RouteLink("Read More", "Details", new { action = "Details", id = item.newsId, category = item.categoryName, newsName = item.newsName })
Use :
Read More
Make sure your route is not overridden by other route. So put your route first in RoutConfig.cs
Change your code to:
foreach (var item in Model)
{
Read More
}//change name=item.newsName to newsName=item.newsName
Also make sure that your controller has correct signature as per your routing details:
public class NewsController : Controller
{
public ActionResult Details(int id, string category, string newsName )
}
First URL Correct
Read More
You may Route Debugger whenever yo see issue related to routes

ASP.Net MVC: So wait... The Default Route Parameter Has To Be Named id?

Has anyone else had this issue? I have to be doing something wrong.
So I'm setting up a route for errors like this:
routes.MapRoute
(
"SharedError",
"Shared/Error/{error}",
new { error = "" }
);
And calling like:
return parentController.RedirectToRoute("SharedError", new RouteValueDictionary(new { error = errorMessage.ToString() }));
And on the controller:
public ActionResult Error(String error)
Simple right? Well when this is actually run, error is null despite the url looking like:
/Shared/Error/ThisIsTheError
But the error parameter in the Error method is null. (And yes I've tried other words)
Now if I replace all that with the word 'id' everything works.
Global.asax.cs
routes.MapRoute
(
"SharedError",
"Shared/Error/{id}",
new { id = "" }
);
Redirect:
return parentController.RedirectToRoute("SharedError", new RouteValueDictionary(new { id = errorMessage.ToString() }));
Shared Controller:
public ActionResult Error(String id)
Is id a must have word for all routes if you have a default route taking in a value?
You always need to specify the controller and action parameters:
routes.MapRoute
(
"SharedError",
"Shared/Error/{error}",
new { controller = "Shared", action="Error", error = "" }
);
I'm guessing that the reason why using id works for you is because you have the default route still registered, which has id as a parameter and default values for controller and action.
Note, if you still have the default route, make sure you add your route before it, otherwise it will match the other one first.

ASP.net MVC Areas and creating an ActionLink with ID (SEO / clean URL)

I am building a Help Desk Ticket system for a client using ASP.NET MVC 1.0 / C#. I have implemented Steven Sanderson's "App Areas in ASP.NET MVC, Take 2" and it is working great.
In my Globabl.asax page I have some routes defined as such:
public static void RegisterRoutes(RouteCollection routes)
{
// Routing config for the HelpDesk area
routes.CreateArea("HelpDesk", "ProjectName.Areas.HelpDesk.Controllers",
routes.MapRoute(null, "HelpDesk/{controller}/{action}", new { controller = "Ticket", action = "Index" }),
routes.MapRoute(null, "HelpDesk/Ticket/Details/{TicketId}", new { controller = "Ticket", action = "Details", TicketId = "TicketId" })
);
}
So, if I enter "http://localhost/HelpDesk/Ticket/Details/12" in the browser address bar manually, I get the results I expect. Here is my controller:
public ActionResult Details(int TicketId)
{
hd_Ticket ticket = ticketRepository.GetTicket(TicketId);
if (ticket == null)
return View("NotFound");
else
return View(ticket);
}
In my view I have:
<%= Html.ActionLink(item.Subject, "Details", new { item.TicketId } )%>
But that code generates "http://localhost/HelpDesk/Ticket/Details?TicketId=12" which also returns the expected results. My Question is...
How do I define an ActionLink when using Steven Sanderson's Areas that will create a clean URL like: "http://localhost/HelpDesk/Ticket/Details/12" ?
Try
<%= Html.ActionLink(item.Subject, "Details", new { TicketId = item.TicketId } )%>
The ActionLink method expects a dictionary with keys that match the parameter names. (Note that passing an anonymous object is a convenience for this). Anything else I believe it will just tag onto the end of the URL.
EDIT: The reason that this isn't working for you is because your first route matches and takes precedence (controller and action), but defines no TicketId parameter. You need to switch the order of your routes. You should always put your most specific routes first.
Try
<%= Html.ActionLink(item.Subject, "Details", new { TicketId=item.TicketId } )%>
I think Womp has it ...
Oh and while you are swapping your routes try
routes.MapRoute(null, "HelpDesk/Ticket/Details/{TicketId}", new { controller = "Ticket", action = "Details"})
I think the , TicketId = "id" is messing things up
Hope that helps,
Dan

Resources