why model posted to action Display in view? - asp.net-mvc

have 2 action with same name.(AddNewUser) one of them work with HttpGet and another with HttpPost.
[HTTPGet]
public ActionResult AddNewUser()
{
User user = Utilities.SessionProvider.GetCurrentUser();
if (user.ID_User == 0)
return Redirect("Apps.kosarfci.ir");
RoleType role = (RoleType)RoleDeterminer.RoleDeterminate();
if (role != RoleType.Center)
{
return RedirectToAction("Restriction");
}
return View("VNewUser");
}
[HttpPost]
public ActionResult AddNewUser(VMNewUser InModel)
{
User user = Utilities.SessionProvider.GetCurrentUser();
if (user.ID_User == 0)
return Redirect("Apps.kosarfci.ir");
RoleType role = (RoleType)RoleDeterminer.RoleDeterminate();
if (role != RoleType.Center)
{
return RedirectToAction("Restriction");
}
IUserBL centerUserBL = new CenterUserBL();
InModel.User.UserName = InModell.User.NationalCode;
InModel.User.Password = InModell.User.PersonalCode;
bool confirmedBL = centerUserBL.AddUser(InModel.User);
_msgList.Add(new Message() { MsgType = MessageType.Success, MsgContent = MessageProvider.GetMessage(MessageContent.Submit_Success_NewUser) });
ViewBag.Message = _msgList;
return View("VNewUser");
}
AddNewUser() ,return a form with input entry and then form submited to AddNewUser(VMNewUser InModel). but after that a form with filled entry with posted model is displayed. i expect that a form with blank input entry display because i dont send pre-filled model(VMNewUser) in to the view.
why?
--VMNewUser--
#model PersonManagement.Views.User.VMNewUser
<style>
table{
font-family:Tahoma;
}
</style>
#using (Html.BeginForm("AddNewUser", "User", FormMethod.Post))
{
<table>
<tr>
<td>name</td>
<td>#Html.TextBoxFor(f=>f.User.FirstName)</td>
</tr>
<tr>
<td>family</td>
<td>#Html.TextBoxFor(f=>f.User.LastName)</td>
</tr>
<tr>
<td>personalcode</td>
<td>#Html.TextBoxFor(f=>f.User.PersonalCode)</td>
</tr>
<tr>
<td>nationalcode</td>
<td>#Html.TextBoxFor(f=>f.User.NationalCode)</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="create" style="font-family:Tahoma;float:left" /></td>
</tr>
</table>
}

The main reason for sending back the populated model is to prevent the user from having to re-populate the form if there is an error processing the request server-side. It also provides the client with information about what fields failed and if there are any particular error messages that should be displayed.
It's recommended you use the PRG pattern therefore if the request is successful, you would redirect the user to a new page. In your case, you could redirect the user back to AddNewUser action which would present the user with the empty form again e.g.
return RedirectToAction("AddNewUser");

Way 1:
In your HttpPost method return to Action instead of returning view like this:
return RedirectToAction("AddNewUser");
Way 2:
or simply return View() without passing Model object which means null model and the fields will not be populated obviously:
return View();
Way 3 :
you can also do like this, if Model is valid save data and return View with empty fields, otherwise return view with populated data to user.
Like this :
[HttpPost]
public ActionResult AddNewUser(VMNewUser InModel)
{
if(ModelState.IsValid)
{
User user = Utilities.SessionProvider.GetCurrentUser();
if (user.ID_User == 0)
return Redirect("Apps.kosarfci.ir");
RoleType role = (RoleType)RoleDeterminer.RoleDeterminate();
if (role != RoleType.Center)
{
return RedirectToAction("Restriction");
}
IUserBL centerUserBL = new CenterUserBL();
InModel.User.UserName = InModell.User.NationalCode;
InModel.User.Password = InModell.User.PersonalCode;
bool confirmedBL = centerUserBL.AddUser(InModel.User);
_msgList.Add(new Message() { MsgType = MessageType.Success, MsgContent = MessageProvider.GetMessage(MessageContent.Submit_Success_NewUser) });
ViewBag.Message = _msgList;
return View();
}
else
{
return View(InModel);
}
}

Related

Model after post not change why

I have Page for Both Insert User and this work fine but after I insert new info i send new model but this not work.the info that i insert before are still in textbox without any error. why???
return View(new User());
#using (#Html.BeginForm("RegisterUser", "UserManagement", FormMethod.Post))
{
#Html.AntiForgeryToken()
<table class="Registertbl">
<tr>
<td>نام*</td>
<td> #Html.TextBoxFor(m => m.FName, new { maxlength = 20})<br />
</td>
<td>سمت*</td>
<td>#Html.TextBoxFor(m => m.Post, new { maxlength = 200})</td>
</tr>
</table>
<br />
<input type="submit" value="Insert" class="insertBtn" />
#Html.ActionLink("back", "ViewUserList", "UserManagement")
}
//Controller
[HttpGet]
public ActionResult RegisterUser()
{
return View(new User());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RegisterUser(Common.UsersManagement.Entities.User model)
{
SetUserManagement();
var Result = userManagement.RegisterUser(model);
if (Result.Mode == Common.Extensions.ActionResultMode.Successfully)
{
return View(new User());
}
// if not Successfull
return View(model);
}
maf748 is correct, you should Post-Redirect-Get. You can communicate to the GET action method using TempData that a message should be displayed, e.g.
TempData.Message = "User registered.";
return RedirectToAction( "RegisterUser" );
Then in your RegisterUser view you can check if TempData.Message has a value.
However, if after all that you still want do do it your way you could try ModelState.Clear() before returning the new View. The problem this will cause is that if the user refreshes the page in their browser it will send them back to your Post method, prompting them in the browser with that awful "do you want to resubmit your data" message and potentially creating duplicate registrations in your database.
Try redirecting back to the GET RegisterUser.
The reason is: when you submit a form to MVC, all the values in the ModelState (basically the Request values) take precedence over any model you pass to the view. The redirect will give you an empty ViewDataDictionary, so all values will be pulled from the Model you're passing (the new User())
if (Result.Mode == Common.Extensions.ActionResultMode.Successfully)
{
return RedirectToAction("RegisterUser");
}

Accessing HTML Form data in MVC controller

I have this problem. I need to access data that the user inputs via the statement during the controller method.
Here's my code, maybe this will make it more clear:
// client side
#using (Html.BeginForm())
{
if (competitorList.Count > 0 && eventList.Count > 0)
{
foreach (Event evt in eventList)
{
<table>
<tr><th>#evt.activity.Name</th></tr>
<tr>
<th>Name</th>
<th>Email</th>
<th>Score</th>
<th>New Score</th>
<th>Update</th>
</tr>
#foreach (Results res in resultList)
{
if (res.EventID == evt.id)
{
string competitorName = Person.getUserByEmail(res.CompetitorEmail).FirstName + Person.getUserByEmail(res.CompetitorEmail).LastName;
<tr>
<td>#competitorName</td>
<td>#res.CompetitorEmail</td>
<td>#res.Score</td>
<td><form action="EventResults"><input type="text" name="score" id="score" /></form></td>
<td>#Html.ActionLink("Update", "UpdateResults", "Competition", new { compId = evt.competitionId, evtId = res.EventID, email = res.CompetitorEmail }, null)</td>
</tr>
}
}
</table>
<hr />
}
}
else
{
<p>There are currently no competitors invited to participate</p>
}
}
// controller
public ActionResult UpdateResults(FormCollection form, int compId, int evtId, string email)
{
////// this returns 0.0 /////
double score = Convert.ToDouble(form["score"]);
BINC.Models.Results.UpdateResults(evtId, email, score);
List<Event> CompetitionEvents = Event.getEventsByCompetitionId(compId);
ViewBag.CompetitionEvents = CompetitionEvents;
List<Competitor> Competitors = Competitor.getCompetitors(compId);
ViewBag.Competitors = Competitors;
List<Results> Results = Competition.getCompetitorResultsPairings(CompetitionEvents, Competitors);
ViewBag.Results = Results;
ViewBag.Competition = Competition.getCompetitionById(compId);
return View("EventResults");
}
What you see in the controller method doesn't work; I assume it's because the page wasn't actually "submitted"? I really want to use a link instead of a submit button though. Can someone give me a hand?
give it the ActionType like [HttpPost],[HttpGet],[HttpDelete]
[HttpPost]
public ActionResult UpdateResults(FormCollection form, int compId, int evtId, string email)
{
//Code
}
If you want to use a link, you are using a GET request not a post request.
Your options using a link are either make it an ajax request (see my prior answer at MVC3 Html.ActionLink Post)
or use javascript to post the form:
How can I use an anchor tag to submit a form with jquery
$(document).ready(function(){
$("a").click(function(){
$("#requestNew").submit();
});
});
or using $("#yourHrefId") if you want to refer by id rather than all hrefs.

Clear fields after success

I have a page with 2 input type=text..
#model MVC3.ViewModel.TalkToUsVM
#using (Html.BeginForm())
{
<ul>
<li>#Html.TextBoxFor(m => m.TalkToUsRequest.Name)</li>
<li>#Html.TextBoxFor(m => m.TalkToUsRequest.Email)</li>
</ul>
<input type="submit" value="Save"/>
}
in my controller I do this:
[HttpPost]
public ActionResult Create(TalkToUsRequest talkToUsRequest)
{
var vm = new TalkToUsVM();
if (TryValidateModel(talkToUsRequest))
{
vm.Result = "Success";
return View("Create",vm);
}
vm = new TalkToUsVM
{
Result = "Errrooooooor",
TalkToUsRequest = talkToUsRequest
};
return View(vm);
}
so the problem.. when my model is valid, I set the result to "Success" and in this point vm.TalkToUsRequest is null.. but when page is rendered, all fields are with the same value that when I submited.. even I setting vm.TalkToUsRequest = null!!
How can I clear this fields?
So in this scenario you have to clear your model state if you return back to the same view.
Try following:
ModelState.Clear();
return View(vm);
}
Your answer :
TryUpdateModel(yourmodelname);
and it will update your view state
and if you also want to clear all Modelstate.error at the same time you can
also use :
ModelState.Clear();

Can't login to my own login page

I've created my own login page but when i try to sign in by clicking the submit button it jumps right to the "catch" where it returns View() instead of redirecting to Admin. I can't seem to find any information about it by googling it. I have also tried to remove try and catch and got this exception: "InvalidOprationException was unhanded by user code" Sequence contains no elements.
Here's my login method:
public class LoginController : Controller
{
public static byte[] lagHash(string innString)
{
var algoritm = System.Security.Cryptography.MD5.Create();
byte[] data, utdata;
data = System.Text.Encoding.ASCII.GetBytes(innString);
utdata = algoritm.ComputeHash(data);
return utdata;
}
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(FormCollection innAdmin)
{
string Username = innAdmin["Username"];
try
{
byte[] passwordArray;
passwordArray = createHash(innAdmin["Password"]);
var db = new Models.DataClass1DataContext();
var Admin = (from s in db.Admins
where s.Username == Username &&
s.Password == passwordArray
select s).Single();
if (Admin.Username == innAdmin["Username"])
{
return RedirectToAction("Admin", "Admin");
}
else
{
return View();
}
}
catch (Exception wrong)
{
return View();
}
}
Here is the code for the aspx file:
<table>
<tr>
<td>Username :</td>
<td>
<input type = "text" name="Username" />
</td>
</tr>
<tr>
<td>Password :</td>
<td>
<input type = "password" name="Password" />
</td>
</tr>
<tr>
<td>
<input type = "submit" value="Log In" />
</td>
</tr>
enter code hereIt seems that you need to convert your byte array to a string. Use the proper enconding and convert to a string.
public static string ByteArrayToString(byte[] bytes, EncodingType encodingType)
{
System.Text.Encoding encoding=null;
switch (encodingType)
{
case EncodingType.ASCII:
encoding=new System.Text.ASCIIEncoding();
break;
case EncodingType.Unicode:
encoding=new System.Text.UnicodeEncoding();
break;
case EncodingType.UTF7:
encoding=new System.Text.UTF7Encoding();
break;
case EncodingType.UTF8:
encoding=new System.Text.UTF8Encoding();
break;
}
return encoding.GetString(bytes);
}
* EDIT *
try the following:
var admin = (from s in db.Admins where s.Username == Username && s.Password == passwordArray select s).SingleOrDefault();
if (admin != null)
{
return RedirectToAction("Admin", "Admin");
}
else
{
return View();
}
* EDIT 2 *
That means your validation is failing.
Try this:
var test = (from s in db.Admins where s.Username == Username select s).SingleOrDefault();
if (test != null)
{
var test2 = test.Password;
}
place a breakpoint and examine the test object. It should not be null.
Look at the retrieved password and compare it against the hashed one you are using.
You are closing in now.
** EDIT 3 **
Well, then that means the problem is with your datastore. The username you are using to login just does not exist, therefore login can never succeed!

Modelstate with Ajax Form

I'm using an AJAX form to update an item to the database. When it gets done, it returns a partial view that re-lists all the items and displays them all in a table. The problem occurs when I have to add a modelstate error in my controller action. I don't want to return the list of items when there is a modelstate error because I want to show the user the error using the ValidationMessage. My thinking is that I could do something like this in my controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UpdateNewsItem(int newsID, string newsTitle, string newsDescription, string newsBeginningDate, string newsEndingDate)
{
List<Models.News> lstNewsItem = new List<News>();
//we need to grab the member so we can capture the user id
//for the corresponding news property
MembershipUser member = Membership.GetUser(User.Identity.Name);
//the news instance to use in case the viewdata is invalid
Models.News newsError = new Models.News();
//create the datetime objects
DateTime dtBeginningDate = DateTime.MinValue;
DateTime dtEndingDate = DateTime.MaxValue;
//the message we want to send whenever the user enters an invalid date
string strInvalidDateError = "Invalid date. Please use a format like '12/25/2008'";
//clean user input
newsTitle = Models.clsGlobals.CleanString(newsTitle);
newsDescription = Models.clsGlobals.CleanParagraph(newsDescription);
//newsTitle
if (string.IsNullOrEmpty(newsTitle))
{
newsError.Title = string.Empty;
ModelState.AddModelError("newsTitle", "You must enter a news title.");
}
//description
if (string.IsNullOrEmpty(newsDescription))
{
newsError.Description = string.Empty;
ModelState.AddModelError("newsDescription", "You must enter a news description.");
}
//beginningDate
if (string.IsNullOrEmpty(newsBeginningDate))
{
ModelState.AddModelError("newsBeginningDate", "You must enter a beginning date.");
}
//endingDate
if (string.IsNullOrEmpty(newsEndingDate))
{
ModelState.AddModelError("newsEndingDate", "You must enter an ending date.");
}
//set the beginning date
try
{
dtBeginningDate = DateTime.Parse(newsBeginningDate);
newsError.BeginningDate = dtBeginningDate;
}
catch (FormatException)
{
ModelState.AddModelError("newsBeginningDate", strInvalidDateError);
}
//set the ending date
try
{
dtEndingDate = DateTime.Parse(newsEndingDate);
newsError.EndingDate = dtEndingDate;
}
catch (FormatException)
{
ModelState.AddModelError("newsEndingDate", strInvalidDateError);
}
//data is validated, so we can begin the update
if (ModelState.IsValid == true)
{
try
{
//use to perform actions on db
Models.NewsDataContext dcNews = new Models.NewsDataContext();
//fetch the items that match what the user requested to edit
lstNewsItem = this.GetNewsItem(newsID);
//set news properties
foreach (Models.News news in lstNewsItem)
{
news.UserId = (Guid)member.ProviderUserKey;
news.Title = newsTitle;
news.Description = newsDescription;
news.EntryDate = DateTime.Now;
news.BeginningDate = dtBeginningDate;
news.EndingDate = dtEndingDate;
}//next
//update the transaction
dcNews.SubmitChanges();
//update the news list
return PartialView("NewsList", this.GetNewsItems());
}
//just to make sure everything goes as planned,
// catch any unhandled exceptions
catch (Exception ex)
{
ModelState.AddModelError("_FORM", ex);
}//end catch
}//end if valid modelstate
//invalid modelstate, so repopulate the viewdata and
//send it back
//the list to hold the entries
List<Models.News> lstErrorNewsItems = new List<Models.News>();
//set the remaining error properties
newsError.UserId = (Guid)member.ProviderUserKey;
newsError.NewsID = newsID;
newsError.EntryDate = DateTime.Now;
//add the item--there will only be one
//but the view is expecting a list so we will
//treat it like one
lstErrorNewsItems.Add(newsError);
return PartialView("EditNews", lstErrorNewsItems);
}//end actionresult
The problem is that when a modelstate error occurs, the modelstate viewdata isn't returned. I suspect it's possibly because I'm not specifying an update target id. But I can't set another updatetargetid because I already have one. Any ideas?
if (!Model.IsValid) {
return PartialView("YourEditForm");
}
else
{
return View("YourIndexView");
}
Should work fine for redisplaying your edit form with validation errors and all.
ViewData gets populated from Post data.
Big Update
I've made some testing to figure it out. And came up with a working test project.
here are some listings:
My Testing controller
public class TestController : Controller
{
//
// GET: /Test/
List<TestData> data;
public TestController()
{
data = new List<TestData>();
for (var i = 0; i < 10; i++)
{
data.Add(new TestData(){Name=string.Format("TestData{0}",i.ToString().PadLeft(4,'0'))});
}
}
public ActionResult Index()
{
return View( data);
}
public ActionResult Edit(string name)
{
if (Request.IsAjaxRequest())
{
return PartialView("AjaxEdit", new TestData() { Name = name });
}
return View(new TestData() { Name = name });
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(TestData testData)
{
ModelState.AddModelError("name", "incorrect name");
if (!ModelState.IsValid)
{
if (Request.IsAjaxRequest())
{
return PartialView("AjaxEdit");
}
}
return View();
}
}
My Edit View:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AjaxValidationPartial.Models.TestData>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit</h2>
<div id="editForm">
<% Html.RenderPartial("AjaxEdit",Model );%>
</div>
</asp:Content>
My Ajax Partial Edit View
" %>
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "editForm" }))
{%>
<fieldset>
<legend>Fields</legend>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name")%>
<%= Html.ValidationMessage("Name", "*")%>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
And my TestData model class
public class TestData
{
public string Name { get; set; }
}
with this code it works just as you wanted.
notice that i do not pass any model to partial view in my "Post" Edit action.
View that gets rendered gets all the values it needs from a post request.
Alright, I've figured it out. Thanks for the response. For future reference, what I had to do was set up one master divider that all of my content goes into. Then, I always set the updateTargetID to that divider so that it doesn't matter what content it displays, just that it displays it. This actually turns out to be easier because you don't have to waste Javascript functions setting other div tags on and off because you're only using one that is continuously updated.

Resources