Why is MVC attribute routing not matching this GUID? - asp.net-mvc

I'm trying to use attribute routing. For various reasons, one of my Guid argments required for a password reset must not be in the queryString so I've had to put it in the path. That itself isn't a problem, except for the fact that I can't get the resetToken to populate in my controller - even when it matches the controller method based on on the Route attribute I have defined.
So given this URL:
http://example.com/Account/ResetPasswordBySMS/96b7ba88-65e0-4dbc-a012-e69545a29a55/?userid=9d394579-afbb-49c4-ba21-877f4dad91fa
...would not populate "resetToken" here? (it's always null)

Change your action to this:
[Route("~/Account/ResetPasswordBySMS/{resetToken?}")]
public ActionResult ResetPasswordBySMS(string resetToken, [FromQuery] string userId, [FromQuery] string code)
{
var guidResetToken= new Guid(resetToken);
}
I tested url http://localhost:55480/Account/ResetPasswordBySMS/96b7ba88-65e0-4dbc-a012-e69545a29a55?userid=9d394579-afbb-49c4-ba21-877f4dad91fa&code=fghjk in Postman. It is working.
And it is not a good idea to mix query string with routing.I would add userId and code to routing too:
[Route("~/Account/ResetPasswordBySMS/{resetToken?}/{userId?}/{code?}
public ActionResult ResetPasswordBySMS(string resetToken, string userId, string code)
I can see the url error - slash after reset token and before ? mark. This slash should be gone.

Related

How to pass value to httpget ActionResult

The Url bellow i am passing and wanted to receive value from my httpget ActionResult method. I already tested and getting error HTTP Error 404.0 - Not Found. Any idea to correct url or whats the solution?
http://localhost:53081/Dashboard/UpdatePassword/Email=John#gmail.com/Token=809a5bc2-5f1b-ce5b0203ff1b
[HttpGet]
public ActionResult UpdatePassword(string Email, string Token)
{
using (var db = new MyappEntities())
{
return View();
}
}
Parameter are used as query strings unless you setup routing for them in the pattern you want. Therefore your URL should look like
http://localhost:53081/Dashboard/UpdatePassword?Email=John#gmail.com&Token=809a5bc2-5f1b-ce5b0203ff1b
This is an incorrect way to pass the parameters. You need to follow the query string format (notice that # is encoded):
http://localhost:53081/Dashboard/UpdatePassword?Email=John%40gmail.com&Token=809a5bc2-5f1b-ce5b0203ff1b
Another option would be
http://localhost:53081/Dashboard/UpdatePassword/John%40gmail.com/809a5bc2-5f1b-ce5b0203ff1b
but that requires additional setup in your routing config, and frankly looks a bit off.
Updated url, try this:
http://localhost:53081/Dashboard/UpdatePassword?Email=John#gmail.com&Token=809a5bc2-5f1b-ce5b0203ff1b
You can read more about what a querystring is:
https://www.dotnetperls.com/querystring

MVC Route conflict seems strange

I am using MVC 5.1 with AutoFac.
I dont understand why the below route from each controller conflict with this URL: https://localhost:44300/Home/login
I thought it would map to the first method. I get this error though:
Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.
The request has found the following matching controller types:
AllThings.WebUI.Controllers.AccountController
AllThings.WebUI.Controllers.PostController
public class AccountController : Controller
{
//
// GET: /Account/Login
[Route("~/{site}/Login")]
[Route("~/Account/Login")]
[Route("~/{country:maxlength(2)}/{site}/Login")]
[Route("~/{country:maxlength(2)}/Account/Login")]
[AllowAnonymous]
public ActionResult Login(string returnUrl, string country, string site)
{
return View();
}
}
public class PostController : Controller
{
[Route("~/{site}/{CategoryUrl?}")]
[Route("~/{country:maxlength(2)}/{site}/{CategoryUrl?}", Name = "ResultList")]
[AllowAnonymous]
public ActionResult List(string country, string site, SearchCriteriaViewModel searchCriteriaViewModel)
{
return View("List", searchCriteriaViewModel);
}
}
The main problem is that you have 3 possible routes that can match /Home/Login.
[Route("~/{site}/Login")]
[Route("~/Account/Login")]
[Route("~/{site}/{CategoryUrl?}")]
Liberal use of placeholders, especially that is all you have in a URL template definition is not a good thing. You should use literals in the URL or if you use placeholders, there should be constraints on them so they don't conflict.
Note that the following routs conflict as well:
[Route("~/{country:maxlength(2)}/{site}/Login")]
[Route("~/{country:maxlength(2)}/Account/Login")]
[Route("~/{country:maxlength(2)}/{site}/{CategoryUrl?}", Name = "ResultList")]
Any one of them could match UK/Account/Login.
Additionally, using a tilde (~) is to override a route prefix (see the MSDN documentation). If your controller doesn't define one, you should just start with the first segment or placeholder.

Query String from BeginForm in MVC 3

I want to use BegingForm with Get method and this is what I do
#using (Html.BeginForm("Search","Home",FormMethod.Get))
{
//My input elements
}
public class HomeController : Controller
{
public ActionResult Search(string queryString)
{
}
}
but query string always comes back as null. I think, I need to do something with route but no luck
routes.MapRoute(
"SearchRoute", // Route name
"Home/Search{queryString}", // URL with parameters
new { controller = "Home", action = "Search", filter = UrlParameter.Optional } // Parameter defaults
);
Obviously, the coming url to the server is something like
Home/Search?query="blah"&query2="blah"&query3="blah"
What am I doing wrong? What is the correct way to get the query parameters in my controller when I want to use get with beginform?
Also, what if the content of my BeginForm can change and so the query string parameter names could be different depending on the rendered page but I want one Search method that analyze the query string and do the right thing?
Also, is a way for them to query parameters to come in a dictionary?
Obviously, the coming url to the server is something like
Home/Search?query="blah"&query2="blah"&query3="blah"
That's how HTML <form> with method GET works and this has nothing to do with ASP.NET MVC, it's plain HTML. You can't do much about it other than having your controller action look like this:
public ActionResult Search(SearchViewModel model)
{
...
}
Where SearchViewModel will contain properties for each input field on this form. Also you don't need this SearchRoute as it won't work that way.
This being said you could probably use javascript in order to subscribe for the onsubmit event of the form, cancel the default submission (which exhibits the behavior you are observing currently), manually fetch all the values inside your form and then manually generate the url you want and redirect to it using window.location.href = '....';. I am mentioning this only for completeness but absolutely not as something that I recommend or that you should ever do.
If you want to get the items from the query string, just use the "Request" object from the ControllerBase:
public ActionResult Search()
{
var queries = new List<string>();
foreach (var parameter in Request.QueryString)
{
queries.Add(parameter.ToString());
}
//Do Stuff with the query parameters...
return View("Index");
}
And "Request.QueryString" is a dictionary just as you wanted :)

How to change action parameters and get it to work without changing routing in asp.net mvc?

In my route I have something like this:
controller/action/{id}
To my knowledge this means it will call any action with the parameter id like the following:
public ActionResult Detail(string id)
{
}
What do I have to do to make the following work without registering the particular route in global.asax file:
public ActionResult Detail(string customerId)
{
}
If you really don't want to rename the method parameter, you can use BindAttribute to tell MVC what its logical name should be:
public ActionResult Detail([Bind(Prefix = "id")] string customerId)
You can also pass customerId as query string, which is normally what I do:
<%: Html.ActionLink("Detail", "Detail", new { #customerId = Model.CustomerID}, null)%>
MVC does not enforce the routing, but rather try to resolve routing based on your url AND query string.
have a route like - controller/action/{customerId} or just rename the parameter customerId to id and then use it the particular way you want.

How can I access the entire query string in an ASP.net controller action

I know that if I have an url like XController/Action?id=1, and an action method
void Action(int id)
the id parameter will automatically be read from the query string.
But how can I access the entire query string when I don't in advance know the name of all parameters. E.g:
void Action(QueryStringCollection coll) {
object id = coll["id"];
}
Is it possible to do something like this?
Use Request.QueryString for this
Request.QueryString.Keys gives you the name of all parameters

Resources