MVC return View not calling controller - asp.net-mvc

I'm extremely new to MVC, but am battling with an issue that is probably very basic and obvious.
On my HomeController, I have:
[HttpGet]
public ViewResult Index()
{
int hour = DateTime.Now.Hour;
var reply = User.Identity.IsAuthenticated ? User.Identity.Name + " is Logged in!" : hour < 12 ? "Good morning" : "Good afternoon";
ViewBag.Greeting = reply;
return View();
}
When I start my application, this code runs.
The page as a link to a Login screen.
<div>
#Html.ActionLink("Login", "ShowLoginScreen")
</div>
The page loads, and the user logs in.
The login cshtml file loads, and the user has a username/password to enter:
<body>
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<p>Username: #Html.TextBoxFor(x=>x.Username)</p>
<p>Password: #Html.TextBoxFor(x=>x.Password)</p>
<p><input type="submit" value="Login"/></p>
}
</body>
When clicking Login, it calls a method in my HomeController:
[HttpPost]
public ActionResult ShowLoginScreen(Login login)
{
if (ModelState.IsValid)
{
var reply = new BasicFinanceService.UserService().Authenticate(login.Username,
Security.EncryptText(login.Password));
if(reply.Id != 0)
FormsAuthentication.SetAuthCookie(reply.Username, false);
return View("Index");
}
return View();
}
The code runs, it goes back to Index, BUT the method in the Home Controller for 'Index' doesn't run. The page just gets rendered without any breakpoint in my "public ViewResult Index()" being called.
Can anyone tell me where I am going wrong?

It's because you're simply returning the output of the view with:
return View("Index");
That doesn't actually invoke the controller action, it simply returns the view. To do what you want, you need to use RedirectToAction:
return RedirectToAction("Index");

Related

How to return to same url after submit button clicked from different ActionResult method in same controller using MVC5?

I want url to be remain same what it was before after submit is clicked, I don't want to display ActionResult method name
Before executing below code, my url was http://localhost/ProjectName/
[HttpPost]
public ActionResult ControllerSignIn(Models.SignIn signin)
{
ViewBag.name = "John";
return View("~/Views/Home/Index.cshtml");
}
After executing the above code, my URL become http://localhost/ProjectName/ControllerSignIn/
I tried below code also
[HttpPost]
public ActionResult ControllerSignIn(Models.SignIn signin,string returnUrl)
{
ViewBag.name = "John";
return View(returnUrl);
}
my partial view code
#using (Html.BeginForm("ControllerSignIn", "Home"))
{
//.... some text box
#Html.Hidden("returnUrl", this.Request.RawUrl)
<input type="submit" class="btn btn-sm btn-primary btn-rounded" value="Login" id="btnLoginSubmit" />
}
Note
My point is, wherever user logged in, after they logged in, it has to visit the same url
You need to realize that URL determines which controller and action should be executed. What you pass to a View() is not a URL, but a path. This path determines which view should be displayed...
// no matter what you put in "SomePath", your URL will remain the same.
return View("SomePath");
If you want to change the URL to http://localhost/ProjectName/ you need to redirect to that Controller's action:
[HttpPost]
public ActionResult ControllerSignIn(Models.SignIn signin)
{
ViewBag.name = "John";
/* return View("~/Views/Home/Index.cshtml"); <-- this has no effect on URL */
return RedirectToAction("MyController", "MyAction"); // this would take you to a different URL
}
If you want to redirect to: http://localhost/ProjectName/ (I assume ProjectName is your Controller and you want to redirect to the default action)... you need to return:
return RedirectToAction("ProjectName"); // redirect to default action of ProjectName controller

How to call a HttpPost ActionResult from a view in another controller in mvc

I want to show my login form in Home Index view,
and when user clicks the login button i want to authenticate him with an action result called (Login) in my Account controller..
this is my code in Home Index view :
#model Charity.Models.ViewModels.LoginModel
#using (Html.BeginForm("Login", "Account", FormMethod.Post))
{
<div>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
</div>
<div>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
</div>
<input type="submit" value="Login" />
}
And this is my Login method:
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
return RedirectToAction("Index", "Admin");
}
else
{
ModelState.AddModelError("", "User or password is incorrect");
}
}
return View();
}
The problem is : when the credentials are correct , the website redirects to /Admin/Index and this is ok ..
but when the credentials are wrong , website redirects to /Account/Login . and my login form is not in this address..
how can i force login actionresult to redirect to /Home/Index when the credentils are wrong ??
Other than an extra closing </div> tag that doesn't appear to belong to any opening tag, your view seems valid.
What is most likely happening is that you decorated your AccountController with the AuthorizeAttribute:
[Authorize]
public class AccountController : Controller
{
/* your code */
}
If you do that, you have to decorate any actions that don't need authorization with the AllowAnonymousAttribute. That includes the versions that are supposed to handle the POST event:
[HttpPost]
[AllowAnonymous]
public ActionResult Login(Models.ViewModels.LoginModel model, string returnUrl = "")
{
/* your code */
}
If you don't decorate the POST version with the AllowAnonymousAttribute, the AuthorizeAttribute is going to trigger a HTTP 401 result, and you get redirected to the login action.
Thats my implemetation of the login method:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null) // user.IsConfirmed
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If this point is reached , an error has occurred; Show form again .
return View(model);
change your return view() in login to
return View("~/Views/Home/Index.cshtml")
the view will be home/index.cshtml ,but location address not change
and if in you home controller index action ,set data for view,it will run also in login action
if you want location change,use redirect and pass some param

MVC Parent Child actions page rendering?

I am learning to embed a child action inside a parent action, and render the whole page properly when a form is submitted from the child action.
ParentAction.cshtml--------------------------------------
#model Web1.Models.ParentActionModel
#{ViewBag.Title = "ParentAction";}
<h2>Parent Action</h2>
#Html.ValidationSummary(true, "Please correct parent errors and try again.")
#using (Html.BeginForm()) {
//parent forminput stuff
<input type="submit" value="Parent Button" />
}
#Html.Action("ChildAction","Home") <!-- ChildAction is included here -->
ChildAction.cshtml (included in parent.cshtml) ------------
#model Web1.Models.ChildActionModel
#{ViewBag.Title = "ChildAction";}
<h2>Child Action</h2>
#Html.ValidationSummary(true, "Please correct child errors and try again.")
#using (Html.BeginForm("ChildAction", "Home")) {
//child form input stuff
<input type="submit" value="Child Button" />
}
HomeController.cs-----------------------
public ActionResult ParentAction() {
return View();
}
[HttpPost]
public ActionResult ParentAction(ParentActionModel pmodel) {
//do model update stuff
return View(pmodel);
}
[ChildActionOnly]
public ActionResult ChildAction() {
return PartialView();
}
[HttpPost]
public ActionResult ChildAction(ChildActionModel cmodel) {
//do model update stuff
return PartialView(cmodel); // <---This is wrong, What's the correct way to do it?
}
Now, when I click the "Child Button", I will only get the view of the child action (durrr!), how do I fix it to generate full page parent+children view? It seems like a logic easy enough, but I am stuck on it for hours.
So, if I removed the [ChildActionOnly] in HttpPost Details method,
when I click submit, only the Details.cshtml partialView is returned,
not with the Master.cshtml, which is not what I want, neither.
That's because you should not return a PartialView in this case, but a full View:
[HttpPost]
public virtual ActionResult Details(DetailsModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
return RedirectToAction("Success");
}
You might also need to only conditionally render the Details action to avoid infinite loops:
#if (!IsPost)
{
#Html.Action("Details", "Home")
}
Obviously if you want to preserve the original context you were in when you invoked this POST action, you will have to use AJAX and then invoke this POST action with AJAX and replace only the corresponding part of the DOM.

MVC 3 StackOverflowException w/ #Html.Action()

I've looked over a bunch of other reports of this, but mine seems to be behaving a bit differently. I am returning PartialViewResults for my child actions, so that's not the source of the recursion. Here's a dumbed down version of what I have.
// The Controller
[ChildActionOnly]
public ActionResult _EditBillingInfo()
{
// Generate model
return PartialView(model);
}
[HttpPost]
public ActionResult _EditBillingInfo(EditBillingInfoViewModel model)
{
// Update billing informatoin
var profileModel = new EditProfileViewModel()
{
PartialToLoad = "_EditBillingInfo"
};
return View("EditProfile", profileModel);
}
[ChildActionOnly]
public ActionResult _EditUserInfo()
{
// Generate model
return PartialView(model);
}
[HttpPost]
public ActionResult _EditUserInfo(EditUserInfoViewModel model)
{
// Update user informatoin
var profileModel = new EditProfileViewModel()
{
PartialToLoad = "_EditUserInfo"
};
return View("EditProfile", profileModel);
}
public ActionResult EditProfile(EditProfileViewModel model)
{
if (String.IsNullOrEmpty(model.PartialToLoad))
{
model.PartialToLoad = "_EditUserInfo";
}
return View(model);
}
// EditProfile View
#model UPLEX.Web.ViewModels.EditProfileViewModel
#{
ViewBag.Title = "Edit Profile";
Layout = "~/Views/Shared/_LoggedInLayout.cshtml";
}
<div>
<h2>Edit Profile</h2>
<ul>
<li class="up one"><span>#Ajax.ActionLink("Account Information", "_EditUserInfo",
new AjaxOptions { UpdateTargetId = "EditProfileDiv", LoadingElementId = "LoadingImage" })</span></li>
<li class="up two"><span>#Ajax.ActionLink("Billing Information", "_EditBillingInfo",
new AjaxOptions { UpdateTargetId = "EditProfileDiv", LoadingElementId = "LoadingImage" })</span></li>
</ul>
<img alt="Loading Image" id="LoadingImage" style="display: none;" src="../../Content/Images/Misc/ajax-loader.gif" />
<div id="EditProfileDiv">
#Html.Action(Model.PartialToLoad)
</div>
</div>
The partial views are both forms for updating either the user information or billing information.
I debugged through this and found what is happening, but cannot figure out why. When a user browses to EditProfile, it load up with the _EditUserInfo partial and the form is there for editing. When you change some info and submit the form it hangs and you get a StackOverflowException in the EditProfile view on the call to #Html.Action(). What happens is on the initial visit to EditProfile, the #Html.Action calls the HttpGet version of _EditUserInfo. You make some changes to the user info and click submit. Once the information is updated the EditProfile view is returned again, but this time #Html.Action calls the HttpPost version of _EditUserInfo which updates the user information again, returns the EditProfile view again and the #Html.Action calls the HttpPost version of _EditUserInfo... You get where this is going. Why after form submission does it call the post version and not the get version like it did for the initial visit to EditProfile?
Thanks for any help!
I might be getting this a bit wrong, it's been a long day so, but in EditProfile you set PartialToLoad (if it's empty) to "_EditUserInfo", then in _EditUserInfo you set it again to _EditUserInfo, won't this create a loop that behaves as what you are experiencing?

How do I redirect to the previous action in ASP.NET MVC?

Lets suppose that I have some pages
some.web/articles/details/5
some.web/users/info/bob
some.web/foo/bar/7
that can call a common utility controller like
locale/change/es or authorization/login
How do I get these methods (change, login) to redirect to the previous actions (details, info, bar) while passing the previous parameters to them (5, bob, 7)?
In short: How do I redirect to the page that I just visited after performing an action in another controller?
try:
public ActionResult MyNextAction()
{
return Redirect(Request.UrlReferrer.ToString());
}
alternatively, touching on what darin said, try this:
public ActionResult MyFirstAction()
{
return RedirectToAction("MyNextAction",
new { r = Request.Url.ToString() });
}
then:
public ActionResult MyNextAction()
{
return Redirect(Request.QueryString["r"]);
}
If you want to redirect from a button in the View you could use:
#Html.ActionLink("Back to previous page", null, null, null, new { href = Request.UrlReferrer})
If you are not concerned with unit testing then you can simply write:
return Redirect(ControllerContext.HttpContext.Request.UrlReferrer.ToString());
A suggestion for how to do this such that:
the return url survives a form's POST request (and any failed validations)
the return url is determined from the initial referral url
without using TempData[] or other server-side state
handles direct navigation to the action (by providing a default redirect)
.
public ActionResult Create(string returnUrl)
{
// If no return url supplied, use referrer url.
// Protect against endless loop by checking for empty referrer.
if (String.IsNullOrEmpty(returnUrl)
&& Request.UrlReferrer != null
&& Request.UrlReferrer.ToString().Length > 0)
{
return RedirectToAction("Create",
new { returnUrl = Request.UrlReferrer.ToString() });
}
// Do stuff...
MyEntity entity = GetNewEntity();
return View(entity);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(MyEntity entity, string returnUrl)
{
try
{
// TODO: add create logic here
// If redirect supplied, then do it, otherwise use a default
if (!String.IsNullOrEmpty(returnUrl))
return Redirect(returnUrl);
else
return RedirectToAction("Index");
}
catch
{
return View(); // Reshow this view, with errors
}
}
You could use the redirect within the view like this:
<% if (!String.IsNullOrEmpty(Request.QueryString["returnUrl"])) %>
<% { %>
Return
<% } %>
In Mvc using plain html in View Page with java script onclick
<input type="button" value="GO BACK" class="btn btn-primary"
onclick="location.href='#Request.UrlReferrer'" />
This works great. hope helps someone.
#JuanPieterse has already answered using #Html.ActionLink so if possible someone can comment or answer using #Url.Action
I'm using .Net Core 2 MVC , and this one worked for me,
in the controller use
HttpContext.Request.Headers["Referer"];
Pass a returnUrl parameter (url encoded) to the change and login actions and inside redirect to this given returnUrl. Your login action might look something like this:
public ActionResult Login(string returnUrl)
{
// Do something...
return Redirect(returnUrl);
}
You could return to the previous page by using ViewBag.ReturnUrl property.
To dynamically construct the returnUrl in any View, try this:
#{
var formCollection =
new FormCollection
{
new FormCollection(Request.Form),
new FormCollection(Request.QueryString)
};
var parameters = new RouteValueDictionary();
formCollection.AllKeys
.Select(k => new KeyValuePair<string, string>(k, formCollection[k])).ToList()
.ForEach(p => parameters.Add(p.Key, p.Value));
}
<!-- Option #1 -->
#Html.ActionLink("Option #1", "Action", "Controller", parameters, null)
<!-- Option #2 -->
Option #2
<!-- Option #3 -->
Option #3
This also works in Layout Pages, Partial Views and Html Helpers
Related: MVC3 Dynamic Return URL (Same but from within any Controller/Action)
For ASP.NET Core
You can use asp-route-* attribute:
<form asp-action="Login" asp-route-previous="#Model.ReturnUrl">
Other in details example:
Imagine that you have a Vehicle Controller with actions
Index
Details
Edit
and you can edit any vehicle from Index or from Details, so if you clicked edit from index you must return to index after edit
and if you clicked edit from details you must return to details after edit.
//In your viewmodel add the ReturnUrl Property
public class VehicleViewModel
{
..............
..............
public string ReturnUrl {get;set;}
}
Details.cshtml
<a asp-action="Edit" asp-route-previous="Details" asp-route-id="#Model.CarId">Edit</a>
Index.cshtml
<a asp-action="Edit" asp-route-previous="Index" asp-route-id="#item.CarId">Edit</a>
Edit.cshtml
<form asp-action="Edit" asp-route-previous="#Model.ReturnUrl" class="form-horizontal">
<div class="box-footer">
<a asp-action="#Model.ReturnUrl" class="btn btn-default">Back to List</a>
<button type="submit" value="Save" class="btn btn-warning pull-right">Save</button>
</div>
</form>
In your controller:
// GET: Vehicle/Edit/5
public ActionResult Edit(int id,string previous)
{
var model = this.UnitOfWork.CarsRepository.GetAllByCarId(id).FirstOrDefault();
var viewModel = this.Mapper.Map<VehicleViewModel>(model);//if you using automapper
//or by this code if you are not use automapper
var viewModel = new VehicleViewModel();
if (!string.IsNullOrWhiteSpace(previous)
viewModel.ReturnUrl = previous;
else
viewModel.ReturnUrl = "Index";
return View(viewModel);
}
[HttpPost]
public IActionResult Edit(VehicleViewModel model, string previous)
{
if (!string.IsNullOrWhiteSpace(previous))
model.ReturnUrl = previous;
else
model.ReturnUrl = "Index";
.............
.............
return RedirectToAction(model.ReturnUrl);
}

Resources