ASP.NET MVC Login ReturnUrl always NULL? - asp.net-mvc

Using Forms Authentication in ASP.NET MVC when trying to log back into a site, it puts a ReturnUrl parameter in the query string. My Logon action method accepts a "returnUrl" string. However it seems that returnUrl string is always null, even when it is clearly in the query string. Any thoughts on why this might be the case or a possible fix?

This tends to happen when you're using one generic logon form, but you're explicitly specifying the Controller and ActionMethod (which is causing a form post, but losing the querystring)
Just to clarify, this is what your code should look like in your BeginForm:
Html.BeginForm("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] })
EDIT: This is by design as RickAnd mentions in comments below. However it doesn't allow for the UI pattern of being deep in a site, clicking on LogOn, then returning to the page you were previously on, if it allows anonymous users. It's a commonly requested pattern. David Allen's approach to LogOff would also work nicely for a clean redirect at LogOn.

Maybe you don't include the ReturnURL parameter into you login form's action attribute, thus posting to a URL without that parameter?

Basically, The Asp.net MVC has some hidden features. For Example when you pass variable 'id' to controller action, it interprets 'id' as default identifier and puts it on browser query with fore slash.By using another name instead of 'id' we will see '?' rather than fore slash. Because of setting the 'id' name on RegisterRoutes method on global.asax file.
In this Problem you have created a custom data passer to controller by using this code:
using(Html.BeginForm("LogOn", "Account", FormMethod.Post))
{
//form fields
}
So Asp.net MVC ignores other useful data to pass to controller action, and we'll see returnUrl always null.
While, by using this, Asp.net MVC acts Correctly and returnUrl is mounted:
using(Html.BeginForm())
{
//form fields in LogOn View
}
By the way, When we use custom data passer to controller action, must pass another data manually like this:
using(Html.BeginForm("LogOn", "Account", new {ReturnUrl = Request.QueryString["ReturnUrl"] }))
{
//form fields
}

There are two ways I can think of to deal with logon and logoff scenarios.
Dave Beer outlined one way, above.
There is another approach that works in many situations. I used it when I coded the NerdDinner tutorial. The tutorial provides us with a logoff function that logs you off and takes you home. I did not want that. I wanted to return to the page I was on before I logged off. So I modified my Account controller logoff action to look like this
public ActionResult LogOff()
{
FormsService.SignOut();
return Redirect(Request.UrlReferrer.ToString());
}
You can get fancier and pass in a returnUrl and test for it, in case you want to override this behavior. But I don't need that. This achieves the desired result. The Logon can work similarly. Maybe there are ways to use the MVC framework to do this for me, but until I learn them, this is VERY simple and works reliably.

Try the following:
public static MvcForm BeginForm(this HtmlHelper htmlHelper, string id)
{
string formAction = htmlHelper.ViewContext.HttpContext.Request.RawUrl;
TagBuilder tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttribute("id", id);
tagBuilder.MergeAttribute("action", formAction);
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(FormMethod.Post), true);
HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
}
First ensure you have set the login url in the web.config, Next, ensure your Signin Form does not contain anything like action, for example:
View:
If you specify action you will always get null for return url:
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SignIn(string userName, string password, bool? rememberMe, string returnUrl)
{
}

Related

Reload page but get a 404 error because of wrong url when routing in MVC

My View is called Survey.cshtml. My current url is http://localhost:17471/Campaign/Survey/6184.
In this page I have a drop down menu to select language. There are English and Spanish. One I select the language, I want to reload the page because some context are shown in different language. I still want to keep the same url.
My code in Survey.cshtml.
$("#id").change(function () {
var selectedValue = $(this).find('option:selected').text();
window.location.href = "#Url.Action("Survey1", "Campaign", new {id=Model.SurveyModel.CampaignId, languageName = "languageToken" })".replace("languageToken", selectedValue);
});
However it goes to the url http://localhost:17471/Campaign/Survey1/6184?languageName=Spanish
My controller CampaignController.cs has the methods.
public ActionResult Survey(int id)
{
// omitted code
return View(model);
}
[HttpPost]
public ActionResult Survey1(int id, string languageName)
{
// omitted here
var view = "Survey";
return View(view,model);
}
I don't have Route for the above methods in RouteConfig.cs. I am not very strong on MVC Routing. Sometimes I am confused the old-and-good HTTP URL ENCODING with the http://site-address/page.html?param1=value1&param2=value2 and the MVC ROUTING which uses the form of http://site-address/page/value1/value2.
So help me.
Your Survey1 action is decorated with [HttpPost], which means you have to use the POST method from your client. But when you do a redirect with window.location.href, that always uses the GET method. You have two options:
Change your controller action and remove [HttpPost].
Create a form with the POST method and your values in it, and use javascript to trigger the submit event on that form instead of using window.location.href.

ASP.NET MVC catch URL parameter in Controller

I've defined such a controller ViewProfile.
I want to use it for the next syntax to access public user info in my project.
/ViewProfile/Sammy
/ViewProfile/Billy
etc...
But I don't know how to handle the 2-nd parameter in URL.
I've tried to use:
[HttpGet]
public ActionResult Index(string query)
{
...
return View();
}
But in the debugger, string query is always empty.
I have read about routines mapping, but really don't understand how would it help me with the determination of id or other parameters.
I read in ASP.NET MVC Book that to get the parameter directly in the controller action just name it as ID.
ASP.NET MVC lets you easily do this without having to confi gure
anything extra. ASP .NET MVC’s default routing convention is to treat
the segment of a URL after the action method name as a parameter named
ID. If your action method has a parameter named ID, then ASP.NET MVC
will automatically pass the URL segment to you as a parameter.
I just tried a sample app and it worked fine for me. The string i entered in the URL did get passed on to the ID parameter in the action.
Also what i noticed is that you should provide your URL as viewprofile/index/1 or
viewprofile/index/somestring.
YOu seem to be skipping the action part.

Asp mvc redirect without affecting url

I have a rather archaic login system, and this is part of the login action:
// login action
return RedirectToAction("Action", new {
id = aVal,
name = aName,
// other params
});
It redirects the user to the Action action, and i noticed that name and the other params ended up being part of the final url scheme. I need to pass all those values to Action.
[HttpGet]
public ActionResult Action(int id, string name, ...) {
Is it possible to pass them to Action and having the url like this: /Controller/Action/123.
I need to restrict the Action method to only those who pass through the login action, the long url + query string make it almost impossible to make it through, but is there another more profesional way to do it.
Thanks and greetings to the SO and SE community.
In order to get Restful styled url's you need to setup an appropriate route.
So in your case something like
routes.MapRoute("MyRoute", "MyController/MyAction/{id}/{name}", new { controller = "MyController", action = "MyAction" });
you can see some other examples here
The second part of your question is more vague - you may want to tag your class with an [Authorize] attribute and then override OnAuthorization where you can do any checks. Not sure if this is what you are looking for.
There is an example of this here

MVC3 - How do I pass a model reference with RedirectToAction

I have a login screen. When the login fails I don't want to return to that same screen with something like this:
return View(model);
What I would like to use is the following to take me to another screen:
return RedirectToAction("Index", "Home");
But how can I pass the model? I see some suggestions but these are related to MVC2. Is there some new feature with MVC3 that would allow me to do this?
Using the RedirectToAction method is basically calling Repsonse.Redirect(Server.Transfer, I always got those mixed up...but anyways). In order to get the ViewModel to that redirected action, you would have to send the parameters of the model in the URL string
return RedirectToAction("Index", "Home", new {prop1 = something, prop2 = something...etc});
However, there is no reason you cannot leverage off of TempData dictionary to maintain the ViewModel and not pass it in the URL parameters.
TempData["ViewModelItem"] = myViewModel;
Return RedirectToAction("Index", "Home");
public ActionResult Index(){
var model = (ViewModelType)TempData["ViewModelItem"];
}
NOTE The above code does not take into account null reference or type checking on the TempData item, which you would want to do.
You can use the MVCContrib strongly typed redirect to action: link
public ActionResult PayWithCreditCard(int id, Buyer user)
{
return this.RedirectToAction<AuctionController>(x => x.Pay(user, id));
}
There is no need to pass the model to RedirectToAction, as all this method does is to generate HTTP 301. This is NOT an equivalent of Server.Transfer.
You can use Html.Partial() to render a common control passing a certain model, or Html.Action() [see: http://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx]
It is considered outside of the proper design to call a controller method directly from another controller method. If you have some common functionality you want to reuse in multiple controllers then you should refactor it out to a separate entity (a service, maybe).
You might also want to taker a look at 13. Use PRG Pattern for Data Modification:
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx

How do you redirect to a page using the POST verb?

When you call RedirectToAction within a controller, it automatically redirects using an HTTP GET. How do I explicitly tell it to use an HTTP POST?
I have an action that accepts both GET and POST requests, and I want to be able to RedirectToAction using POST and send it some values.
Like this:
this.RedirectToAction(
"actionname",
new RouteValueDictionary(new { someValue = 2, anotherValue = "text" })
);
I want the someValue and anotherValue values to be sent using an HTTP POST instead of a GET. Does anyone know how to do this?
For your particular example, I would just do this, since you obviously don't care about actually having the browser get the redirect anyway (by virtue of accepting the answer you have already accepted):
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index() {
// obviously these values might come from somewhere non-trivial
return Index(2, "text");
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(int someValue, string anotherValue) {
// would probably do something non-trivial here with the param values
return View();
}
That works easily and there is no funny business really going on - this allows you to maintain the fact that the second one really only accepts HTTP POST requests (except in this instance, which is under your control anyway) and you don't have to use TempData either, which is what the link you posted in your answer is suggesting.
I would love to know what is "wrong" with this, if there is anything. Obviously, if you want to really have sent to the browser a redirect, this isn't going to work, but then you should ask why you would be trying to convert that regardless, since it seems odd to me.
HTTP doesn't support redirection to a page using POST. When you redirect somewhere, the HTTP "Location" header tells the browser where to go, and the browser makes a GET request for that page. You'll probably have to just write the code for your page to accept GET requests as well as POST requests.
If you want to pass data between two actions during a redirect without include any data in the query string, put the model in the TempData object.
ACTION
TempData["datacontainer"] = modelData;
VIEW
var modelData= TempData["datacontainer"] as ModelDataType;
TempData is meant to be a very short-lived instance, and you should only use it during the current and the subsequent requests only! Since TempData works this way, you need to know for sure what the next request will be, and redirecting to another view is the only time you can guarantee this.
Therefore, the only scenario where using TempData will reliably work is when you are redirecting.
try this one
return Content("<form action='actionname' id='frmTest' method='post'><input type='hidden' name='someValue' value='" + someValue + "' /><input type='hidden' name='anotherValue' value='" + anotherValue + "' /></form><script>document.getElementById('frmTest').submit();</script>");
I would like to expand the answer of Jason Bunting
like this
ActionResult action = new SampelController().Index(2, "text");
return action;
And Eli will be here for something idea on how to make it generic variable
Can get all types of controller
I have just experienced the same problem.
The solution was to call the controller action like a function:
return await ResendConfirmationEmail(new ResendConfirmationEmailViewModel() { Email = input.Email });
The controller action:
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> ResendConfirmationEmail(ResendConfirmationEmailViewModel input)
{
...
return View("ResendConfirmationEmailConfirmed");
}

Resources