(MVC)How to RedirectToAction and keep the content of a Html.Textbox in MVC4? This is my controller how do I fix it and what goes in the view?
[HttpPost]
public ActionResult Index(string ssn)
{
var exist = false;
var record = _db.Citations.Where(u => u.SSN == ssn).FirstOrDefault();
if (record != null)
{
exist = true;
return RedirectToAction("EditDetails", new { id = record.CitationID });
}
else
{
return RedirectToAction("Index", "SubmitAward", ssn); // wiped out ssn! I need to keep the ssn
// so that the user can fill out the form.
}
If your get action is like this:
public ActionResult Index(string ssn)
{
.........
..........
.........
}
then do like this:
return RedirectToAction("Index", "SubmitAward", new { ssn = ssn});
but if it is the same index view of post action which is posted in question, you can pass the object back to view if your view is strongly typed to this class:
return View(record);
Try below code
return RedirectToAction("Index", "SubmitAward", new { ssn = ssn});
And your redirect action will be
public ActionResult Index(string ssn)
{
ViewBag.SSN=ssn;
return View(record);
}
And your view will contain textbox like
#Html.TextBox("SSN",ViewBag.SSN)
It may helps you..
Related
I am using custom Login for my application. I want to insert last login date and time in database and show last login date and time when user login into application.
Controller Code:
public class HomeController : Controller
{
MyDatabaseEntities db = new MyDatabaseEntities();
//
// GET: /Home/
public ActionResult Index()
{
if(Session["LoggedUserID"]!= null)
{
return View();
}
else
{
return RedirectToAction("Login");
}
}
public ActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(Login l)
{
if (ModelState.IsValid)
{
using(MyDatabaseEntities db = new MyDatabaseEntities())
{
this.UpdateLoginLastUpdateStatus();
var v = db.Logins.Where(a => a.UserName.Equals(l.UserName) && a.Password.Equals(l.Password)).FirstOrDefault();
if (v!= null)
{
Session["LoggedUserID"] = v.UserID.ToString();
Session["LoggeduserName"] = v.UserName.ToString();
Session["LastLogin"] = v.LastWebLogin.ToString();
return RedirectToAction("Index");
}
}
}
if(!ModelState.IsValid)
{
ModelState.AddModelError("","Username or Password is incorrect!!");
}
return View(l);
}
public void UpdateLoginLastUpdateStatus()
{
Login l = new Login();
l.LastWebLogin = DateTime.Now.ToString();
db.SaveChanges();
}
[HttpGet]
public ActionResult LogOff()
{
Session.Abandon();
return RedirectToAction("Login", "Home");
}
}
}
Index View
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#if (Convert.ToString(Session["LoggedUserID"]) != "")
{
<section>
<p class="toplink">#Html.ActionLink("Logout", "LogOff", "Home")</p>
</section>
}
Last Logged on: #Session["LastLogin"]
You have been logged in.
I am able to Log In and Log Out but this Last Logged In Time is not working.
The problem is this line is trying to update the login LastWebLogin before you've even retrieved it:
this.UpdateLoginLastUpdateStatus();
You need to call this AFTER you've assigned the Login to the variable v. Additionally, the method is creating a NEW Login class, not using an existing one. For that to work you'd have to pass a parameter v to the method. You don't even need that method really - unless you call it from multiple places and you want to avoid repeated code - it just needs to be a simple as:
var v = db.Logins.Where(a => a.UserName.Equals(l.UserName) && a.Password.Equals(l.Password)).FirstOrDefault();
if (v!= null)
{
// get previous login
var prevLogin = v.LastWebLogin;
// update with current login
v.LastWebLogin = DateTime.Now.ToString();
db.SaveChanges();
Session["LoggedUserID"] = v.UserID.ToString();
... etc
I have the following textbox on an MVC view:
#Html.TextBoxFor(x => x.Captcha, new { #value = "" })
I am trying the textbox to always be empty when the form show after being submited with errors ... But this is not working. I always see the last value.
And this is my controller:
[Route("signup"), HttpGet]
public virtual ActionResult SignUp() {
UserSignUpModel model = new UserSignUpModel();
model.Captcha = String.Empty;
model.Email = "";
return View(model);
} // SignUp
[Route("signup"), HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult SignUp(UserSignUpModel model) {
if (ModelState.IsValid) {
// Create account code
return View(MVC.Shared.Views._Note, new NoteModel("Account created"));
} else {
model.Captcha = String.Empty;
model.Email = "";
return View(Views.SignUp, model);
}
}
Thank You,
Miguel
If your form is submitted with errors, you can simply clear the ViewData and explicitly clear your property in the controller before returning the view with errors.
[HttpPost]
public ActionResult MyController(Model myModel)
{
if (!ModelState.IsValid)
{
myModel.Captcha = String.Empty;
ViewData = null;
return View(myModel);
}
return View(myModel);
}
I was able to solve this. The correct way is to use the model state:
ModelState["Captcha"].Value = new ValueProviderResult("", "", Thread.CurrentThread.CurrentCulture);
This way there is no need to clear other data in ViewData.
And by changing the ModelState, and not removing it, it becomes possible to still display the error associated with that property.
In your action method in your controller set this parameter manually:
// ...
model.Captcha = String.Empty;
return View(model);
And I recommend to add autocomplete=off html attribute to your captcha field:
#Html.TextBoxFor(x => x.Captcha, new { autocomplete = "off" })
I have a question, can this be done using ASP.NET MVC (Razor, and MapRoute)?
Example
Category/ - calls controller Category and Index function
Category/{State_name} - calls controller Category and Cities(State_id) function, returns all cities inside that state.
So URL is displaying state name , but Cities function receive state id?
Yes u can, try
public class CategoryController : Controller {
// GET: /Category/
// OR
// GET: /Category/State_name
public ActionResult Index(string State_name) {
if (!string.IsNullOrWhiteSpace(State_name)) {
int? State_id = FindStateIdFromStateName(State_name); // retrive state_id from datastore where state_name == State_name
if (State_id.HasValue) { // means the currect state_name passed to action
var model = FindStateById(State_id.Value);
return View("Cities", model); // will renders Cities.cshtml with specified model
} else {
// means the specified state_name not found! u can do something else, or allow continue bellow lines
}
}
return View(); // will render normal Index.cshtml
}
}
Let me know if you have any questions or need clarifications on any part.
UPDATE
I have one issue with the way! You get the ID from db with State_name, then get the model from db by State_name! Why not retrieve
model from db by State_name at the first time?
look:
public class CategoryController : Controller {
// GET: /Category/
// OR
// GET: /Category/State_name
public ActionResult Index(string State_name) {
if (!string.IsNullOrWhiteSpace(State_name)) {
var model = FindStateByName(State_name);
if(model != null)
return View("Cities", model);
else
// means the specified state_name not found! u can do something else, or allow continue bellow lines
}
return View(); // will render normal Index.cshtml
}
}
and if you are on EF, then you can create this method:
public State FindStateByName(state_name){
using(var context = new YourEntityContext()){
return context.States.SingleOrDefault(s => s.Name.ToLower() == state_name.ToLower());
}
}
Why not using this way?
This should do it:
routes.MapRoute("Category_byState", "Category/{State_id}", new { controller = "Category", action = "Cities" });
I'd like show a form with some field (one in the example), submit it, save and display the same page with a reset of all fields. The probelm when I submit, I go the "Save" action but when I display the view the form is still filled in.
The model :
public class TestingModel
{
public string FirstName { get; set; }
}
The controller :
public class ChildController : Controller
{
public ActionResult Index()
{
TestingModel model = new TestingModel();
return View(model);
}
public ActionResult Save(TestingModel model)
{
Console.WriteLine(model.FirstName); //OK
//Save data to DB here ...
TestingModel testingModel = new TestingModel() { FirstName = string.Empty };
return View("Index", testingModel);
}
}
The view :
#using (Html.BeginForm("Save", "Child",FormMethod.Post))
{
#Html.TextBoxFor( m => m.FirstName)
<input type="submit" id="btSave" />
}
When Id debug to the view, in "Immediat window" Model.FirstName = "" but when the page is show I still have the value posted. I tried a ReditrectionToAction("Index") at the end of the Save method but same result.
Do you have an idea ?
Thanks,
If you want to do this you need to clear everything that's in the ModelState. Otherwise HTML helpers will completely ignore your model and use data from ModelState when binding their values.
Like this:
[HttpPost]
public ActionResult Save(TestingModel model)
{
//Save data to DB here ...
ModelState.Clear();
TestingModel testingModel = new TestingModel() { FirstName = string.Empty };
return View("Index", testingModel);
}
or simply redirect to the Index GET action in case of success:
[HttpPost]
public ActionResult Save(TestingModel model)
{
//Save data to DB here ...
return RedirectToAction("Index");
}
Try to return Index view without any model
return View("Index");
You should be posting your form back to the same ActionResult
public ActionResult Index()
{
TestingModel model = new TestingModel();
return View(model);
}
[HttpPost]
public ActionResult Index(TestingModel model)
{
Console.WriteLine(model.FirstName); //OK
//Save data to DB here ...
return RedirectToAction("Index");
}
You would be able to use the parameterless overload for BeginForm too
#using(Html.BeginForm())
{
//form
}
I am redirecting the view from [HttpPost] method to [HttpGet] method. I have gotten it to work, but want to know if this is the best way to do this.
Here is my code:
[HttpPost]
public ActionResult SubmitStudent()
{
StudentViewModel model = TempData["model"] as StudentResponseViewModel;
TempData["id"] = model.Id;
TempData["name"] = model.Name;
return RedirectToAction("DisplayStudent");
}
[HttpGet]
public ActionResult DisplayStudent()
{
ViewData["id"] = TempData["id"];
ViewData["name"] = TempData["name"];
return View();
}
View:
<%# Page
Language="C#"
Inherits="System.Web.Mvc.ViewPage"
%>
<html>
<head runat="server">
<title>DisplayStudent</title>
</head>
<body>
<div>
<%= ViewData["id"]%> <br />
<%= ViewData["name"]%>
</div>
</body>
</html>
There are basically 3 techniques in ASP.NET MVC to implement the PRG pattern.
TempData
Using TempData is indeed one way of passing information for a single redirect. The drawback I see with this approach is that if the user hits F5 on the final redirected page he will no longer be able to fetch the data as it will be removed from TempData for subsequent requests:
[HttpPost]
public ActionResult SubmitStudent(StudentResponseViewModel model)
{
if (!ModelState.IsValid)
{
// The user did some mistakes when filling the form => redisplay it
return View(model);
}
// TODO: the model is valid => do some processing on it
TempData["model"] = model;
return RedirectToAction("DisplayStudent");
}
[HttpGet]
public ActionResult DisplayStudent()
{
var model = TempData["model"] as StudentResponseViewModel;
return View(model);
}
Query string parameters
Another approach if you don't have many data to send is to send them as query string parameters, like this:
[HttpPost]
public ActionResult SubmitStudent(StudentResponseViewModel model)
{
if (!ModelState.IsValid)
{
// The user did some mistakes when filling the form => redisplay it
return View(model);
}
// TODO: the model is valid => do some processing on it
// redirect by passing the properties of the model as query string parameters
return RedirectToAction("DisplayStudent", new
{
Id = model.Id,
Name = model.Name
});
}
[HttpGet]
public ActionResult DisplayStudent(StudentResponseViewModel model)
{
return View(model);
}
Persistence
Yet another approach and IMHO the best consists into persisting this model into some data store (like a database or something and then when you want to redirect to the GET action send only an id allowing for it to fetch the model from wherever you persisted it). Here's the pattern:
[HttpPost]
public ActionResult SubmitStudent(StudentResponseViewModel model)
{
if (!ModelState.IsValid)
{
// The user did some mistakes when filling the form => redisplay it
return View(model);
}
// TODO: the model is valid => do some processing on it
// persist the model
int id = PersistTheModel(model);
// redirect by passing the properties of the model as query string parameters
return RedirectToAction("DisplayStudent", new { Id = id });
}
[HttpGet]
public ActionResult DisplayStudent(int id)
{
StudentResponseViewModel model = FetchTheModelFromSomewhere(id);
return View(model);
}
Each method has its pros and cons. Up to you to choose which one suits best to your scenario.
If you are inserting this data into a database then you should redirect them to a controller action that has this data in the route:
/Students/View/1
You can then write code in the controller to retrieve the data back from the database for display:
public ActionResult View(int id) {
// retrieve from the database
// create your view model
return View(model);
}
One of the overrides of RedirectToAction() looks like that:
RedirectToAction(string actionName, object routeValues)
You can use this one as:
[HttpPost]
public ActionResult SubmitStudent()
{
StudentViewModel model = TempData["model"] as StudentResponseViewModel;
return RedirectToAction("DisplayStudent", new {id = model.ID, name = model.Name});
}
[HttpGet]
public ActionResult DisplayStudent(string id, string name)
{
ViewData["id"] = TempData["id"];
ViewData["name"] = TempData["name"];
return View();
}
Hope that works.
This is the classic Post-Redirect-Get pattern (PRG) and it looks fine but I would add one bit of code. In the DisplayStudent method check if your TempData variables are not null otherwise do a redirect to some default Index action. This is in case a user presses F5 to refresh the page.
public ActionResult DisplayStudent()
{
if(TempData["model"] == null)
{
return RedirectToAction("Index");
}
var model = (StudentResponseViewModel)TempData["model"];
return View(model);
}
public ViewResult Index()
{
IEnumerable<StudentResponseViewModel> students = GetAllStudents();
return View(students);
}