Routing with parameter conflicts issue - asp.net-mvc

MY route config :
routes.MapRoute(
"LastTwoRoute",
"thong-ke-ket-qua-xo-so-2-so-cuoi/{cityID}/{pnumbers}/{pdays}/{ponlySpecial}",
new { controller = "LastTwo", action = "Index",
cityID = "MB",
pnumbers = "",
pdays = 1000,
ponlySpecial = false
});
The controller :
[HttpGet]
public ActionResult Index(string cityID, string pnumbers, int pdays, bool ponlySpecial)
{
[HttpGet]
public ActionResult Index(string cityID, string pnumbers, int pdays, bool ponlySpecial)
{
LastTwoParameters lastTwoParameters = new LastTwoParameters();
lastTwoParameters.listCities = Common.GetDropDownCitiesList();
lastTwoParameters.Numbers = pnumbers;
lastTwoParameters.Days = pdays;
lastTwoParameters.OnlySpecial = ponlySpecial;
lastTwoParameters.listLastTwoResult = new List<getReport_LastTwo_Result>();
if (TempData["Redirection"] != null || !string.IsNullOrEmpty(pnumbers) )
{
if (!string.IsNullOrEmpty(cityID) && pdays > 0)
{
using (KQXS context = new KQXS())
{
lastTwoParameters.listLastTwoResult = context.getReport_LastTwo(cityID, pnumbers, pdays, ponlySpecial).ToList();
}
}
}
return View(lastTwoParameters);
}
[HttpPost]//Run action method on form submission
public ActionResult Index(List<Cities> c, string cityID, string numbers, int days, bool onlySpecial)
{
TempData["Redirection"] = true;
return RedirectToRoute("LastTwoRoute", new {
cityID = (string.IsNullOrEmpty(cityID) ? "MB" : cityID ),
pnumbers = (string.IsNullOrEmpty(numbers) ? string.Empty : numbers) ,
pdays = (days == 0 ? 1000 : days),
ponlySpecial = onlySpecial});
}
When I frist access the controller :
and hit the submit button without entering/modifying any parameter, there are no errors :
but if I modify the third or the fourth parameter, I will have this error :
No route in the route table matches the supplied values.
I debuged the code, and at the line RedirectToRoute in HttpPost, every parameters are about the same except the parameter that I modified. I can't think of a reason why is this error happening!
If I enter/modified the second parameter (the second text box counting from top to bottom), I have no errors either!
Any help is greatly appreciated!
P/s : If this is not clarify enough for you because of my poor English, I can provide a screen video which records how I get the error!

You have pnumbers = "" in your route but it's not marked as an optional field (and you wouldn't be able to have it as optional if it's in the middle with required fields around it).
Try defaulting it to "0" or something.
Another alternative is to move this option to the end of the required parameters and mark it as optional like:
pnumbers = UrlParameter.Optional
It's worth installing route debugger if you are having routing issues as it adds a nice interface at the bottom of the page which shows which routes will trigger and which wont. It's essential with complex routes IMO.

Related

CanĀ“t read odata in mvc controller

I have the following url:
http://localhost:64863/api/Entity/getStatus?%24skip=0&%24top=25&%24inlinecount=allpages&_=1473445898026
My question is how can I read skip and top in controller. This is my controller signature:
[HttpGet("getStatus")]
public JsonResult GetStatus(
string filter,
int skip,
int top)
{
The following query string
%24skip=0&%24top=25
will be available in Request.QueryString with the following keys: $skip and $top. You won't be able to change your controller parameter names to $skip and $top since you'll get an error in Visual Studio and won't be able to compile, so you can remove the skip and top parameter and get the %24skip and %24top values from Request.QueryString in your controller
[HttpGet("getStatus")]
public JsonResult GetStatus(
string filter)
{
string skip = string.Empty;
string top = string.Empty;
if (Request.QueryString["$skip"] != null)
{
skip = Request.QueryString["$skip"];
}
if (Request.QueryString["$top"] != null)
{
top = Request.QueryString["$top"];
}
// do whatever you want with skip and top variable
This is the code i added after get QueryString:
private string getParameterFromUrl(string parameter)
{
string url = Request.QueryString.Value;
Match match = Regex.Match(url, parameter + "=([^&]*)");
return match.Result("$1");
}
Where parameter is skip or top in my case

OutputCache attribute and VaryByCustom without parameter

I'm trying to use the OutputCache attribute to cache pages depending on the language users selected.
[OutputCache(Duration = 86400, Location = OutputCacheLocation.Client, VaryByParam = "", VaryByCustom = "lang")]
public ActionResult MyActionMethod()
{
...
}
It works fine when we are on the page and we change the language, cool!
But the thing is: when a user calls the page for the first time, there is no "lang" parameter. So the cache will be created without parameter and it won't be replace if we change the language after.
How can I manage this case, when there is no parameter?
Any help would be appreciated, thanks!
You are talking about there is not "lang" parameter, you mean, there is no "lang" custom?
In global.asax you should have something like this:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom == "lang")
{
string lang = null;
if (Request.UserLanguages != null && Request.UserLanguages.Length > 0)
{
lang = Request.UserLanguages.First().Split(new char[] { ';' }).First();
}
else
{
// Default
lang = "en-US";
}
return string.Format("lang={0}", lang.ToLower());
}
return base.GetVaryByCustomString(context, custom);
}
Then it will have the value "en-US" as default and otherwise get it from the browser in this case, or implement it using cookie.

How to return to calling page, but with a slight difference, in MVC3?

I need to call another MVC3 page(P2) and then return to calling page(P1). However the slight twist is that P2 needs to call itself, so the referrer can end up being P2.
So:
P1 - (P2 -> P2 -> P2) ->P1
So the question is how do I get P1's referrer URL and keep it and then use it later to go back to P1, regardless of the number of time P2 calls itself.
I did try and populate ViewBag.Referrer:
Back
using the following controller code, trying to only set it on the original call. However ViewBag.Referrer always seemed to pick up the P2 Referrer URL, even though in debug mode it was not resetting ViewBag.Referrer due to IsOriginalCall=0. It is weird. It is as if I am storing a pointer and not the value.
public ViewResult Index(int id = 0, int IsOriginalCall = 0)
{
if (IsOriginalCall =1)
{
if (Request.UrlReferrer != null)
{
ViewBag.Referrer = Request.UrlReferrer.LocalPath;
}
}
ViewBag.SLIid = id == 0 ? 4 : id;
return View(db.StdSection.Where(r=>r.InWizard).OrderBy(r=>r.Name).ToList());
}
Thoughts and a solution would be hugely appreciated. I have been going around in circles on this one.
Thanks in advance.
EDIT, Attempt 2 with TempData:
Calling code:
#Html.ActionLink("Sections", "Index","SSLI2", new { id=item.Id, ReturnUrl = Request.Url.ToString() },null)
Controller:
public ViewResult Index(string ReturnUrl, int id = 0)
{
if (ReturnUrl != "x")
{
//ViewBag.Referrer = Request.UrlReferrer.LocalPath;
TempData["Referrer"] = ReturnUrl;
}
ViewBag.SLIid = id == 0 ? 4 : id;
return View(db.StdSection.Where(r=>r.InWizard).OrderBy(r=>r.Name).ToList());
}
View:
Back
Which produces:
Back when P2 goes back to P2, but seems to use P2 referrer URL ????
You could pass the ReferrerUrl in from P1 querystring and then store the value in TempData. It will then survive transition from one action call to another.
Another option would be to pass the ReferrerUrl in from P1 in the querystring and then put the value in a hidden input on P2.
#Html.HiddenFor(m => m.ReferrerUrl)
or
#Html.Hidden("ReferrerUrl", ViewBag.ReferrerUrl)
then pick the value up on each post-back and render it as a hidden input value again.
Edit
You could maybe try doing something like:
public ViewResult Index(string returnUrl, int id = 0)
{
ViewBag.ReturnUrl = returnUrl;
ViewBag.SLIid = id == 0 ? 4 : id;
// This can be picked up in another action method.
TempData["ReturnUrl"] = returnUrl;
return View(db.StdSection.Where(r=>r.InWizard).OrderBy(r=>r.Name).ToList());
}
Then maybe render it using:
Back

ASP.NETMVC routing looping forever

I'm quite new to MVC routing so please bear with me if this is too trivial.
I have created the following route:
routes.MapRoute("ProductSearch", "Category/{CategoryName}/{CategoryID}/{brandName}/{brandID}", new
{
controller = "Search",
action = "Search"
});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
This is entering the Action
Search
just fine at least the first time round (with the correct parameter values). Then it will keep looping forever and lose the parameters. Any idea what might be happening?
[EDIT]
The issue seems to be coming from the fact that I have 4 placeholders. When I only set 2 placeholders the route worked.
The Action:
public ActionResult Search(string query = null, int CategoryID = 0, int brandID = -1)
{
WebSearch search = null;
try
{
int loyaltyCardID = -1;
if (FocusStoreRemoting.UserInfo != null)
{
loyaltyCardID = FocusStoreRemoting.UserInfo.LoyaltyCardID;
}
if (query != null)
{
search = FocusStoreRemoting.Controller.DoWebSearch(FocusStoreRemoting.ClientSession.SessionID,
FocusStoreRemoting.StoreID, loyaltyCardID, queryString: query);
}
else if (CategoryID >= 0)
{
search = FocusStoreRemoting.Controller.DoWebSearch(FocusStoreRemoting.ClientSession.SessionID,
FocusStoreRemoting.StoreID, loyaltyCardID, groupID: CategoryID, brandID: brandID);
}
}
catch (Exception ex)
{
return RedirectToAction("DisplayError", "Error");
}
Session[SessionStrings.SearchItems] = search.StockItems;
return View(search.RefineCategories);
}
Thanks in advance.
[Edit2]
One thing I have discovered is that it is not looping forever but for each link (and any external file) file I have listed in the <head></head> section of the page
The problem was being caused by links to external files. For example:
I was calling the external JavaScript files like so:
src="../../Content/js/whatever"
So when trying to navigate to the file, the absolute URL would be translated to:
http://localhost/Category/TestCategory/1/TestBrand/1/Content/js/whatever
Which MVC's routing was routing to the Search action mentioned in the Question.
So in reality it wasn't "Looping Forever" but for every image/content file the page contained.
I solved this by removing ../../ changing the relative URL to /Content/js/whatever

need help canonicalizing an HTTP GET form in asp.net mvc

I have a form in an asp.net mvc site that serves 3 purposes: paging, sorting, and searching. These items should all be rendered in the same form, since returning the correct search results depends on variables from all 3 aspects. What I'm trying to do is move the parameters out of the querystring and put them in a canonical URL.
I'm almost there, here are my 3 route configurations so far (using T4MVC for area, controller, and action names):
context.MapRoute(null,
"my-area/my-widgets/search/{size}-results-max/page-{page}/order-by-{sort}",
new
{
area = MVC.MyArea.Name,
controller = MVC.MyArea.MyWidgets.Name,
action = MVC.MyArea.MyWidgets.ActionNames.Search,
page = UrlParameter.Optional,
size = UrlParameter.Optional,
sort = UrlParameter.Optional,
}
);
context.MapRoute(null,
"my-area/my-widgets/canonicalize-search",
new
{
area = MVC.MyArea.Name,
controller = MVC.MyArea.MyWidgets.Name,
action = MVC.MyArea.MyWidgets.ActionNames.CanonicalizeSearch,
}
);
context.MapRoute(null,
"my-area/my-widgets",
new
{
area = MVC.MyArea.Name,
controller = MVC.MyArea.MyWidgets.Name,
action = MVC.MyArea.MyWidgets.ActionNames.CanonicalizeSearch,
}
);
The form in the view submits to the CanonicalizeSearch route, using this syntax:
#using (Html.BeginForm(MVC.MyArea.MyWidgets.CanonicalizeSearch(),
FormMethod.Get))
In the MyWidgetsController, there are 2 action methods:
[ActionName("canonicalize-search")]
public virtual RedirectToRouteResult CanonicalizeSearch(string keyword,
int page = 1, int size = 10, string sort = "Title-Ascending")
{
var result = RedirectToRoutePermanent(new
{
area = MVC.MyArea.Name,
controller = MVC.MyArea.MyWidgets.Name,
action = MVC.MyArea.MyWidgets.ActionNames.Search,
page = page,
size = size,
sort = sort,
keyword = keyword,
});
return result;
}
[ActionName("search")]
public virtual ViewResult Search(string keyword,
int page = 1, int size = 10, string sort = "Title-Ascending")
{
// code to perform query
return View(model);
}
This works for moving all querystring variables into a canonicalized route except for the keyword. If I add a keyword parameter to the first route, the CanonicalizeSearch action only redirects to the Search action when keyword is not null, empty, or whitespace. This is no good as it makes browsing page results impossible when there is no keyword entered.
I think I've tried everything -- giving the keyword a default value in the controller, adding a 4th route that adds keyword to the other 3 parameters, etc. However the only way I can seem get this to work is by keeping keyword as a querystring parameter. (Actually I can get it to work by prepending an underscore to the keyword in CanonicalizeSearch and stripping it off in Search, but that's pretty hacky).
Any help?
Did you try setting UrlParameter.Optional on the keyword parameter in your first route? Sounds obvious and dumb, but you never ruled it out.
I think I stumbled on a better solution to this by trying to solve another problem.
Say someone types in "my search terms" in the keyword box. Submitting that causes the CanonicalizeSearch method to route to the path:
/my-area/my-widgets/search/10-results-per-page/page-1/
order-by-Title-Ascending/my%20search%20terms
Those %20 symbols are annoying. I would rather the URL look like this:
/my-area/my-widgets/search/10-results-per-page/page-1/
order-by-Title-Ascending/my-search-terms
I can accomplish this with the following (note the change from a permanent to a temporary redirect):
[ActionName("canonicalize-search")]
public virtual RedirectToRouteResult CanonicalizeSearch(string keyword,
int page = 1, int size = 10, string sort = "Title-Ascending")
{
var result = RedirectToRoute(new
{
area = MVC.MyArea.Name,
controller = MVC.MyArea.MyWidgets.Name,
action = MVC.MyArea.MyWidgets.ActionNames.Search,
page = page,
size = size,
sort = sort,
keyword = (string.IsNullOrWhiteSpace(keyword))
? "no-keywords" : keyword.Replace(' ', '-'),
});
TempData["keyword"] = keyword;
return result;
}
[ActionName("search")]
public virtual ViewResult Search(string keyword,
int page = 1, int size = 10, string sort = "Title-Ascending")
{
keyword = TempData["keyword"] as string ?? keyword;
// code to perform query
return View(model);
}
This solves both the question I posted here and the removal of the %20 symbols. Whenever the keyword is null empty or whitespace, it will render the URL
/my-area/my-widgets/search/10-results-per-page/page-1/
order-by-Title-Ascending/no-keywords
... and the route will always match.

Resources