How to call a action by route specified over action in MVC? - asp.net-mvc

MVC controller code is:
[Route("Home-Appliances")]
public async Task<ActionResult> homeappliances(string q = "", string tags = null, int minPrice = 0, int maxPrice = 50000, bool accessories = false, string condition = null, int? page = null)
{
//my stuff...
}
How can I call this method from view using html helpers?
Note: I don't want to call this by action name. I have to call this by route specified i.e, Home-Appliances

"Home-Appliances" is not the route name, it's the URL. If you want to call it by route name, you need to pass a name:
[Route("Home-Appliances", Name = "HomeAppliances")]
Then, you can do:
Url.RouteUrl("HomeAppliances")

Related

MVC Attribute routing with Url.Action not resolving route

I cannot get #Url.Action to resolve to the url I am expecting based on the attribute route I have applied:
My action (SearchController but with [RoutePrefix("add")])
[Route("{searchTerm}/page/{page?}", Name = "NamedSearch")]
[Route("~/add")]
public ActionResult Index(string searchTerm = "", int page = 1)
{
...
}
Call to Url.Action
#Url.Action("Index", new { controller = "Search", searchTerm = "replaceMe", page = 1 })
This results in a url of
/add?searchTerm=replaceMe&page=1
I would expect
/add/replaceMe/page/1
If I type the url manually then it resolves to the correct action with the correct parameters. Why doesn't #Url.Action resolve the correct url?
Since you have a name for your pretty route definition, you may use the RouteUrl method.
#Url.RouteUrl("NamedSearch", new { searchTerm = "replaceMe", page = 1})
And since you need add in the url, you should update your route definition to include that in the url pattern.
[Route("~/add")]
[Route("~/add/{searchTerm?}/page/{page?}", Name = "NamedSearch")]
public ActionResult Index(string searchTerm = "", int page = 1)
{
// to do : return something
}
Routes are order sensitive. However, attributes are not. In fact, when using 2 Route attributes on a single action like this you may find that it works on some compiles and not on others because Reflection does not guarantee an order when analyzing custom attributes.
To ensure your routes are entered into the route table in the correct order, you need to add the Order property to each attribute.
[Route("{searchTerm}/page/{page?}", Name = "NamedSearch", Order = 1)]
[Route("~/add", Order = 2)]
public ActionResult Index(string searchTerm = "", int page = 1)
{
return View();
}
After you fix the ordering problem, the URL resolves the way you expect.
#Url.Action("Index", new { controller = "Search", searchTerm = "replaceMe", page = 1 })
// Returns "/add/replaceMe/page/1"
To return full URL use this
#Url.Action("Index", new { controller = "Search", searchTerm = "replaceMe", page = 1}, protocol: Request.Url.Scheme)
// Returns "http://yourdomain.com/add/replaceMe/page/1"
Hope this helps someone.

Attribute Routing with multiple optional parameter

I have a controller named "view" with below action that has multiple optional parameters. I want to use the Attribute Routing to generate URLs like these:
/view/keyword/sometext/country/canada
/view/country/canada
/view/keyword/sometext/country/canada/city/calgary
/view/keyword/sometext/country/canada/state/alberta
/view/country/canada/state/alberta/page/1
As you can see, there could be a various combination of URLs since all of these parameters are optional.
However, if i use like below, i get error if the requested url doesn't match or one of the optional Parameter is null.
[Route("view/keyword/{keyword}/country/{country}/state/{state}/city/{city}/page/{page}")]
public ActionResult Index(int? page, string keyword = "", string city = "", string state = "", string country = "")
{
return view();
}
If i use like below, some of the url works but that would take me to write 20+ new routes depending on number of parameters. I am using MVC 5.
[Route("view/keyword/{keyword}/country/{country}/state/{state}/city/{city}/page/{page}")]
[Route("view/keyword/{keyword}/country/{country}/state/{state}/page/{page}")]
[Route("view/keyword/{keyword}/country/{country}/city/{city}/page/{page}")]
[Route("view/keyword/{keyword}/state/{state}/city/{city}/page/{page}")]
[Route("view/state/{state}/city/{city}/page/{page}")]
public ActionResult Index(int? page, string keyword = "", string city = "", string state = "", string country = "")
{
return view();
}
Any suggestions please?
May be you can add your routes in the RoutesConfig.cs file.
In the RoutesCollection collection of the RegisterRoutes method. placing the default one (which is already present) at the last place.
routes.MapRoute(
"CustomRouteName", // Route name
"view/state/{state}/city/{city}/page/{page}"// URL with parameters
new { controller = "View", action = "Index", state = "", city = "", page="" }
);

RedirectToAction method with multiple route parameters not redirecting

I am using RedirectToAction method and i want to pass two route parameters
but its not redirecting to specified action method.
I am using following code:
return RedirectToAction("abcd", "Registration", new { id = "", loginType = "pqr" });
and the specified action method signature is as :
public ActionResult abcd(string id, string loginType = null)
Is there any mistake in signature??
Thanks...
Make sure that the abcd() action method is in a class called RegistrationController. If your abcd() action method is in the RegistrationController class then you want to call like this:
return RedirectToAction("abcd", new { id = "", loginType = "pqr" });

hide parameters passing to controller in address bar (URL rewrite or something else)

I have the following routes:
routes.MapRoute("Event Overview", "{city}/{type}/{id}",
new {city="LA", controller = "BaseEvent", action = "EventOverview"}, new {city = new CityConstraint()});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
And, several links on my site:
#Html.ActionLink("Make", "EventOverview", "BaseEvent", new { id = eventInfo.Key.OID, type = eventInfo.Key.XPObjectType.TypeName.GetShortTypeName(), activeTab = "#scheduleLink", session = eventInfo.Key.EventSchedules[0].SessionId, hall = eventInfo.Key.EventSchedules[0].HallId, client = eventInfo.Key.EventSchedules[0].BasePlace.PremieraClientId}, null)
#Html.ActionLink("Make", "EventOverview", "BaseEvent", new { id = eventInfo.Key.OID, type = eventInfo.Key.XPObjectType.TypeName.GetShortTypeName(), activeTab = "#scheduleLink", }, null)
This is `EventOverview action:
public ActionResult EventOverview(int id, string type, string activeTab,string hall, string session, string client, string count)
{
var model = CreateEventViewData<EventViewData>(id, type);
model.ActiveTab = activeTab;
model.ScheduleCount = count;
model.SessionId = session;
model.HallId = hall;
model.ClientId = client;
return View("Controls/EventsInfo/EventInfo", model);
}
In the first link passing many parameters, and all shows in browser's address field:
This is for firts link:
http://localhost:62291/LA/Film/36?activeTab=%23scheduleLink&session=15&hall=65&client=2&count=1
This is for second link:
http://localhost:62291/LA/Film/36?activeTab=%23scheduleLink
I want something like that:
http://localhost:62291/LA/Film/36
What ways to hide parameters in an address line are?
UPDATE:
$(document).ready(function () {
var link = $(".btn_buy_ticket").find("a").click(function (e) {
e.preventDefault();
$.post($(this).attr("href"));
});
})
[HttpPost]
public ActionResult EventOverview(int id) // just for test
{
return RedirectToAction("EventOverview", new {id = id});
}
public ActionResult EventOverview(int id, string type, string activeTab,string hall, string session, string client, string count)
{
var model = CreateEventViewData<EventViewData>(id, type);
model.ActiveTab = activeTab;
model.ScheduleCount = count;
model.SessionId = session;
model.HallId = hall;
model.ClientId = client;
return View("Controls/EventsInfo/EventInfo", model);
}
All actions are called, but my EventInfo view not loaded.
You could use POST instead of GET. So you could replace the link with a form containing hidden fields for the parameters that you don't want to appear in the query string:
#using (Html.BeginForm("EventOverview", "BaseEvent", new { id = eventInfo.Key.OID, type = eventInfo.Key.XPObjectType.TypeName.GetShortTypeName() }, FormMethod.Post, null))
{
#Html.Hidden("activeTab", "#scheduleLink")
#Html.Hidden("session", eventInfo.Key.EventSchedules[0].SessionId)
#Html.Hidden("hall", eventInfo.Key.EventSchedules[0].HallId)
#Html.Hidden("client", eventInfo.Key.EventSchedules[0].BasePlace.PremieraClientId)
<button type="submit">Make</button>
}
How to hide URL Parameters
If you want to hide URL parameters, you go to debug properties and you select the radiobutton option and specify thatc
specificpage:
http://localhost:61757/TicketDataUpload/templateupload?projectid=6497&userid=7336
This is the parameter URL. If you want to hide like this:
http://localhost:61757/Controller/index
You have to put in a specific page as when you open the page, it will not display URL parameters.
My (kinda ugly) solution: leave the code behind as is, then after the html doc has loaded (at which point the server has already made use of your query string data), use history.pushState in javascript to change the url in the address bar like so:
$(document).ready(function () {
let hrefWithoutQueryString = window.location.href.split('?')[0];
// args below are 'state' (irrelevant for me), 'title' (so far,
// ignored by most browsers) and 'url' (will appear in address bar)
history.pushState({ }, '', hrefWithoutQueryString);
});
For a split second the query string will appear in the address bar, but after the js above has run, everything including and after the '?' in your url will be gone.
Obviously, a side effect is that it alters your browser's session history but this wasn't an issue for me.
And note that I have passed in an empty state into pushState--again, this was not an issue for me but could cause problems depending on how the routing of your application is set up and whether it makes use of the state variable.

Passing multiple parameters to a controller?

ok. simple one that is wrapping my brain
I have a method that I have in the controller
public ActionResult Details(string strFirstName, string strLastName)
{
return View(repository.getListByFirstNameSurname(strFirstName, strLastName)
}
How do i get multiple parameters from the URL to the controller?
I dont want to use the QueryString as it seems to be non-mvc mind set.
Is there a Route? Or Other mechanism to make this work? Or am I missing something altogehter here with MVC
EDIT
the url that I am trying for is
http://site.com/search/details/FirstName and Surname
so if this was classic asp
http://site.com/search/details?FirstName+Surname
But i feel that i have missed understood something which in my haste to get to working code, I have missed the point that there really should be in a put request - and I should collect this from the formcollection.
Though might be worth while seeing if this can be done - for future reference =>
For example, suppose that you have an action method that calculates the distance between two points:
public void Distance(int x1, int y1, int x2, int y2)
{
double xSquared = Math.Pow(x2 - x1, 2);
double ySquared = Math.Pow(y2 - y1, 2);
Response.Write(Math.Sqrt(xSquared + ySquared));
}
Using only the default route, the request would need to look like this:
/simple/distance?x2=1&y2=2&x1=0&y1=0
We can improve on this by defining a route that allows you to specify the parameters in a cleaner format.
Add this code inside the RegisterRoutes methods within the Global.asax.cs.
routes.MapRoute("distance",
"simple/distance/{x1},{y1}/{x2},{y2}",
new { Controller = "Simple", action = "Distance" }
);
We can now call it using /simple/distance/0,0/1,2
Something like this?:
routes.MapRoute("TheRoute",
"{controller}/{action}/{strFirstName}/{strLastName}",
new { controller = "Home", action = "Index", strFirstName = "", strLastName = "" }
);
or:
routes.MapRoute("TheRoute2",
"people/details/{strFirstName}/{strLastName}",
new { controller = "people", action = "details", strFirstName = "", strLastName = "" }
);
UPDATED:
This route should be placed before "Default" route:
// for urls like http://site.com/search/details/FirstName/Surname
routes.MapRoute("TheRoute",
"search/details/{strFirstName}/{strLastName}",
new { controller = "search", action = "details", strFirstName = "", strLastName = "" }
);
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
Use hidden values in your form
<%= Html.Hidden("strFirstName", Model.FirstName)%>
<%= Html.Hidden("strLastName", Model.LastName)%>
and the model binder will do the binding
public ActionResult Details(string strFirstName, string strLastName)
{
return View(repository.getListByFirstNameSurname(strFirstName, strLastName)
}
It is also possible to use FormCollection:
public ActionResult Details(int listId, FormCollection form)
{
return View(rep.getList(form["firstName"], form["lastName"])
}
Likewise, if the HTTP request contains a form value with the exact same name (case sensitive), it will automatically be passed into the ActionResult method.
Also, just to be clear, there is nothing un-MVC about querystring parameters.
I also had the same problem once and what I did was use the Ajax call inside the jQuery function. First I selected all parameter values using jQuery selectors. Below is my jQuery function.
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$('#btnSendNow').click(function () {
var grid = $('#Patient-kendo-Grid').data('kendoGrid');
var location = $('#EmailTempalteLocation option:selected').text();
var appoinmentType = $('#EmailTemplateAppoinmentType option:selected').text();
var emailTemplateId = $('#EmailTemplateDropdown').val();
var single = $('input:radio[name=rdbSingle]:checked').val();
var data = grid.dataSource.view();
var dataToSend = {
patients: data,
place: location,
appoinment: appoinmentType,
rdbsingle: single,
templateId: emailTemplateId
};
debugger;
$.ajax({
url: 'Controller/Action',
type: 'post',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(dataToSend)
});
});
});
</script>
My controller method has five parameters and it is as below.
[HttpPost]
public ActionResult SendEmailToMany(List<PatientModel> patients, string place, string appoinment, string rdbsingle, string templateId)
{
emailScheduleModel = new EmailScheduleModel();
AmazonSentEmailResultModel result;
List<string> _toEmailAddressList = new List<string>();
List<string> _ccEmailAddressList = new List<string>();
List<string> _bccEmailAddressList = new List<string>();
IEmailTemplateService emailTemplateService = new EmailTemplateService();
EmailTemplateContract template = emailTemplateService.GetEmailTemplateById(new Guid(templateId));
emailScheduleModel.EmailTemplateContract = new EmailTemplateContract();
emailScheduleModel.EmailTemplateContract = template;
}
It is working fine in my developments.
For further details please follow the below url.
http://dushanthamaduranga.blogspot.com/

Resources