ASP.NET MVC Model State Validations - asp.net-mvc

<%= Html.ValidationSummary("Account creation was unsuccessful. Please correct the errors and try again.") %>
</div>
<% using (Html.BeginForm("Register", "Account" , FormMethod.Post))
{ %>
<div>
<fieldset>
<legend>Account Information</legend>
<p>
<label for="username">User Name:</label>
<%= Html.TextBox("username") %>
<%= Html.ValidationMessage("username") %>
</p>
<p>
<label for="FirstName">First Name</label>
<%= Html.TextBox("firstName") %>
<%= Html.ValidationMessage("firstName") %>
</p>
<p>
<label for="LastName">Last Name</label>
<%= Html.TextBox("lastName") %>
<%= Html.ValidationMessage("lastName") %>
</p>
<p>
<label for="email">Email:</label>
<%= Html.TextBox("email") %>
<%= Html.ValidationMessage("email") %>
</p>
<p>
<label for="password">Password:</label>
<%= Html.Password("password") %>
<%= Html.ValidationMessage("password") %>
</p>
<p>
<label for="confirmPassword">Confirm password:</label>
<%= Html.Password("confirmPassword") %>
<%= Html.ValidationMessage("confirmPassword") %>
</p>
<p>
<label for="Role">Role:</label>
<%= Html.DropDownList("Role",((SelectList)ViewData["Roles"]),"--Select One---") %>
</p>
<p>
<input type="submit" value="Register" />
</p>
</fieldset>
</div>
<% } %>
private ModelStateDictionary _modelState;
public AccountController() : this(null, null)
{
_modelState = new ModelStateDictionary();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(string username, string firstName, string lastName, string password, string confirmPassword, string email, string role)
{
try
{
if (string.IsNullOrEmpty(password))
_modelState.AddModelError("password", "passowrd field is empty");
if (string.IsNullOrEmpty(confirmPassword))
_modelState.AddModelError("confirmPassword", "Confim Passowrd field is empty");
if (string.IsNullOrEmpty(username))
_modelState.AddModelError("username", "UserName field is empty");
if (string.IsNullOrEmpty(email))
_modelState.AddModelError("email", "Email field cannot be empty");
Regex regEmail = new Regex(#"\w+([-+.]\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*");
if (!regEmail.IsMatch(email))
_modelState.AddModelError("email", " The email id submitted is not in valid format");
if (string.IsNullOrEmpty(firstName))
_modelState.AddModelError("firstName", "First name field is empty");
if (string.IsNullOrEmpty(lastName))
_modelState.AddModelError("lastName", "Last name field is empty");
if (!password.Equals(confirmPassword, StringComparison.InvariantCultureIgnoreCase))
_modelState.AddModelError("password", "Password do not match");
if (_modelState.IsValid)
{
int id = _UsrService.GetRoleId(role);
Data.User usr = new User(username, firstName, lastName, email, DateTime.Now, null, id);
string retRegister = _UsrService.RegisterUser(usr, password, confirmPassword, "none", "none");
if (retRegister.Equals("true"))
{
UserRolesControl contrl = new UserRolesControl(Users(), Roles());
return View("Control", contrl);
}
else
{
ModelState.AddModelError("_Form", retRegister);
ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
var roles = _UsrService.GetRoles().ToList();
ViewData["Roles"] = new SelectList(roles);
return View();
}
}
else
{
var roles = _UsrService.GetRoles().ToList();
ViewData["Roles"] = new SelectList(roles);
return View();
}
}
catch (Exception ex)
{
return View();
}
}
Above is a registrations form, I am working on validations on it. It does run through fine in the controller method , but it does not display the error messages when it send back to register page. It there anything wrong with my code?

What's _modelState? Why not use ModelState instead?
Or just Data Annotations for client side validation as well.
In this code, you are not returning the ModelState, that is why no errors are showing. Just use ModelState instead of _modelState, and you should be all set.:
if (_modelState.IsValid)
{
//blah
}
else
{
var roles = _UsrService.GetRoles().ToList();
ViewData["Roles"] = new SelectList(roles);
return View();
}

Related

Display Error message on same view

I'm trying to delete a record from the database using MVC 2. currently delete function works fine but there are some records with foreign key relations so i don't wont them to be deleted and when user try to delete such a record i want to show a error message on the delete view without navigating to another view.
Controller:
[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
try
{
// TODO: Add delete logic here
StockRepository rep = new StockRepository();
Stock stock = rep.GetStock(id);
rep.Delete(stock);
rep.Save();
return RedirectToAction("Index");
}
catch
{
//need to display an error message if unable to delete
return View();
}
}
View:
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>Fields</legend>
<div class="display-label">StockID</div>
<div class="display-field"><%: Model.StockID %></div>
<div class="display-label">ClientName</div>
<div class="display-field"><%: Model.ClientName %></div>
<div class="display-label">ItemName</div>
<div class="display-field"><%: Model.ItemName %></div>
<div class="display-label">ItemCount</div>
<div class="display-field"><%: Model.ItemCount %></div>
<div class="display-label">Price</div>
<div class="display-field"><%: String.Format("{0:F}", Model.Price) %></div>
<div class="display-label">OtherExpences</div>
<div class="display-field"><%: String.Format("{0:F}", Model.OtherExpences) %></div>
<div class="display-label">TotalStockValue</div>
<div class="display-field"><%: String.Format("{0:F}", Model.TotalStockValue) %></div>
<div class="display-label">DeliveryDate</div>
<div class="display-field"><%: String.Format("{0:d}", Model.DeliveryDate) %></div>
<div class="display-label">Description</div>
<div class="display-field"><%: Model.Description %></div>
</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="submit" value="Delete" /> |
<%: Html.ActionLink("Back to List", "Index") %>
</p>
<% } %>
Using Viewdata
View
<%
if (ViewData["dbError"] != null)
{
%>
//display ViewData dbError
<%
}
%>
Controllor
[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
try
{
// TODO: Add delete logic here
StockRepository rep = new StockRepository();
Stock stock = rep.GetStock(id);
rep.Delete(stock);
rep.Save();
return RedirectToAction("Index");
}
catch
{
//need to display an error message if unable to delete
**ViewData["dbError"] = "Error message here";**
return View();
}
}

Selected value from drop-down list doesn't post from jquery dialog

I have a jQuery dialog. All of the fields are posting correctly except for the drop-downs, the value is getting passed as null rather than the selected value.
<div id="popupCreateCompany" title="Create a new company">
<form>
<fieldset>
<p>
<label for="company_name">Company Name:</label>
<%= Html.TextBox("company_name") %>
</p>
<p>
<label for="company_desc">Company Description:</label>
<%= Html.TextBox("company_desc") %>
</p>
<p>
<label for="address">Address:</label>
<%= Html.TextBox("address") %>
</p>
<p>
<label for="city">City:</label>
<%= Html.TextBox("city") %>
</p>
<p>
<label for="state">State:</label>
<%= Html.TextBox("state") %>
</p>
<p>
<label for="zip">Zip:</label>
<%= Html.TextBox("zip") %>
</p>
<p>
<label for="website">Website:</label>
<%= Html.TextBox("website", "http:/") %>
</p>
<p>
<label for="sales_contact">Sales Contact:</label>
<%= Html.DropDownList("sales_contact", Model.SelectSalesContacts, "** Select Sales Contact **") %>
</p>
<p>
<label for="primary_company">Primary Company:</label>
<%= Html.DropDownList("primary_company", Model.SelectPrimaryCompanies, "** Select Primary Company **") %>
</p>
</fieldset>
</form>
jQuery:
$('#popupCreateCompany').dialog(
{
autoOpen: false,
modal: true,
buttons:
{
'Add': function() {
var dialog = $(this);
var form = dialog.find('input:text');
$.post('/company/create', $(form).serialize(), function() {
dialog.dialog('close');
})
},
'Cancel': function() {
$(this).dialog('close');
}
}
});
$("#create-company").click(function() {
$('#popupCreateCompany').dialog('open');
});
My SelectList definitions:
public class SubcontractFormViewModel
{
public subcontract Subcontract { get; private set; }
public SelectList SelectPrimaryCompanies { get; set; }
public MultiSelectList SelectService_Lines { get; private set; }
public SelectList SelectSalesContacts { get; private set; }
public SubcontractFormViewModel(subcontract subcontract)
{
SubcontractRepository subcontractRepository = new SubcontractRepository();
Subcontract = subcontract;
SelectPrimaryCompanies = new SelectList(subcontractRepository.GetPrimaryCompanies(), "company_id", "company_name");
SelectService_Lines = new MultiSelectList(subcontractRepository.GetService_Lines(), "service_line_id", "service_line_name", subcontractRepository.GetSubcontractService_Lines(Subcontract.subcontract_id));
SelectSalesContacts = new SelectList(subcontractRepository.GetContacts(), "contact_id", "contact_name");
}
}
Your problem is this line:
var form = dialog.find('input:text');
You're only serializing <input> elements, not other form elements.
You could add the select elements by changing this to
var form = dialog.find('input:text, select');
or
var form = dialog.find('input:text').add('select');
You need to ensure the dialog is still within the form for the values to post, by default it isn't, like this:
$('#popupCreateCompany').dialog({
autoOpen: false,
modal: true,
buttons:
{
'Add': function() {
var dialog = $(this);
var form = dialog.find('input:text');
$.post('/company/create', $(form).serialize(), function() {
dialog.dialog('close');
})
},
'Cancel': function() {
$(this).dialog('close');
}
}
}).parent().appendTo("#myFormID");
By default, jQuery UI (and some other modals too) append to created modal to the end of the <body>, so the actual <select> element is outside your form, meaning it isn't included in the POST values. If you do the .parent().appendTo() like above, it'll move the dialog wrapped back inside the form and it should be posted correctly.

Form File Upload with other TextBox Inputs + Creating Custom Form Action attribute

I am attempting to create a form where a user is able to enter your typical form values textboxes etc, but also upload a file as part of the form submission. This is my View code it can be seen that the File upload is identified by the MCF id:
<% using (Html.BeginForm("Create", "Problem", FormMethod.Post, new { id = "ProblemForm", enctype = "multipart/form-data" }))
{%>
<p>
<label for="StudentEmail">Student Email (*)</label>
<br />
<%= Html.TextBox("StudentEmail", Model.Problem.StudentEmail, new { size = "30", maxlength=26 })%>
<%= Html.ValidationMessage("StudentEmail", "*") %>
</p>
<p>
<label for="Type">Communication Type (*)</label>
<br />
<%= Html.DropDownList("Type") %>
<%= Html.ValidationMessage("Type", "*") %>
</p>
<p>
<label for="ProblemDateTime">Problem Date (*)</label>
<br />
<%= Html.TextBox("ProblemDateTime", String.Format("{0:d}", Model.Problem.ProblemDateTime), new { maxlength = 10 })%>
<%= Html.ValidationMessage("ProblemDateTime", "*") %>
</p>
<p>
<label for="ProblemCategory">Problem Category (* OR Problem Outline)</label>
<br />
<%= Html.DropDownList("ProblemCategory", null, "Please Select...")%>
<%= Html.ValidationMessage("ProblemCategory", "*")%>
</p>
<p>
<label for="ProblemOutline">Problem Outline (* OR Problem Category)</label>
<br />
<%= Html.TextArea("ProblemOutline", Model.Problem.ProblemOutline, 6, 75, new { maxlength = 255 })%>
<%= Html.ValidationMessage("ProblemOutline", "*") %>
</p>
<p>
<label for="MCF">Mitigating Circumstance Form</label>
<br />
<input id="MCF" type="file" />
<%= Html.ValidationMessage("MCF", "*") %>
</p>
<p>
<label for="MCL">Mitigating Circumstance Level</label>
<br />
<%= Html.DropDownList("MCL") %>
<%= Html.ValidationMessage("MCL", "*") %>
</p>
<p>
<label for="AbsentFrom">Date Absent From</label>
<br />
<%= Html.TextBox("AbsentFrom", String.Format("{0:d}", Model.Problem.AbsentFrom), new { maxlength = 10 })%>
<%= Html.ValidationMessage("AbsentFrom", "*") %>
</p>
<p>
<label for="AbsentUntil">Date Absent Until</label>
<br />
<%= Html.TextBox("AbsentUntil", String.Format("{0:d}", Model.Problem.AbsentUntil), new { maxlength = 10 })%>
<%= Html.ValidationMessage("AbsentUntil", "*") %>
</p>
<p>
<label for="AssessmentID">Assessment Extension</label>
<br />
<%= Html.DropDownList("AssessmentID") %>
<%= Html.ValidationMessage("AssessmentID", "*") %>
<%= Html.TextBox("DateUntil", String.Format("{0:d}", Model.AssessmentExtension.DateUntil), new { maxlength = 16 })%>
<%= Html.ValidationMessage("DateUntil", "*") %>
</p>
<p>
<label for="Details">Assessment Extension Details</label>
<br />
<%= Html.TextArea("Details", Model.AssessmentExtension.Details, 6, 75, new { maxlength = 255 })%>
<%= Html.ValidationMessage("Details", "*") %>
</p>
<p>
<label for="RequestedFollowUp">Requested Follow Up</label>
<br />
<%= Html.TextBox("RequestedFollowUp", String.Format("{0:d}", Model.Problem.RequestedFollowUp), new { maxlength = 16 })%>
<%= Html.ValidationMessage("RequestedFollowUp", "*") %>
</p>
<p>
<label for="StaffEmail">Staff</label>
<br />
<%= Html.ListBox("StaffEmail", Model.StaffEmail, new { #class = "multiselect" })%>
<%= Html.ValidationMessage("StaffEmail", "*")%>
</p>
<p>
<input class="button" type="submit" value="Create Problem" />
</p>
This is my controller code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Problem problem, AssessmentExtension assessmentExtension, Staff staffMember, HttpPostedFileBase file, string[] StaffEmail)
{
if (ModelState.IsValid)
{
try
{
Student student = studentRepository.GetStudent(problem.StudentEmail);
Staff currentUserStaffMember = staffRepository.GetStaffWindowsLogon(User.Identity.Name);
var fileName = Path.Combine(Request.MapPath("~/App_Data"), Path.GetFileName(file.FileName));
file.SaveAs(#"C:\Temp\" + fileName);
if (problem.RequestedFollowUp.HasValue)
{
String meetingName = student.FirstName + " " + student.LastName + " " + "Mitigating Circumstance Meeting";
OutlookAppointment outlookAppointment = new OutlookAppointment(currentUserStaffMember.Email, meetingName, (DateTime)problem.RequestedFollowUp, (DateTime)problem.RequestedFollowUp.Value.AddMinutes(30));
}
problemRepository.Add(problem);
problemRepository.Save();
if (assessmentExtension.DateUntil != null)
{
assessmentExtension.ProblemID = problem.ProblemID;
assessmentExtensionRepository.Add(assessmentExtension);
assessmentExtensionRepository.Save();
}
ProblemPrivacy problemPrivacy = new ProblemPrivacy();
problemPrivacy.ProblemID = problem.ProblemID;
problemPrivacy.StaffEmail = currentUserStaffMember.Email;
problemPrivacyRepository.Add(problemPrivacy);
if (StaffEmail != null)
{
for (int i = 0; i < StaffEmail.Length; i++)
{
ProblemPrivacy probPrivacy = new ProblemPrivacy();
probPrivacy.ProblemID = problem.ProblemID;
probPrivacy.StaffEmail = StaffEmail[i];
problemPrivacyRepository.Add(probPrivacy);
}
}
problemPrivacyRepository.Save();
return RedirectToAction("Details", "Student", new { id = student.Email });
}
catch
{
ModelState.AddRuleViolations(problem.GetRuleViolations());
}
}
return View(new ProblemFormViewModel(problem, assessmentExtension, staffMember));
}
This form was working correctly before I had to switch to using a non-AJAX file upload, this was due to an issue with Flash when enabling Windows Authentication which I need to use.
It appears that when I submit the form the file is not sent and I am unsure as to why? I have also been unsuccessful in finding an example online where a file upload is used in conjunction with other input types.
Another query I have is that for Create, and Edit operations I have used a PartialView for my forms to make my application have higher code reuse. The form action is normally generated by just using:
Html.BeginForm()
And this populates the action depending on which Url is being used Edit or Create. However when populating HTML attributes you have to provide a action and controller value to pass HTML attributes.
using (Html.BeginForm("Create", "Problem", FormMethod.Post, new { id = "ProblemForm", enctype = "multipart/form-data" }))
Is it possible to somehow populate the action and controller value depending on the URL to maintain code reuse? Thinking about it whilst typing this I could set two values in the original controller action request view data and then just populate the value using the viewdata values?
Any help on these two issues would be appreciated, I'm new to asp.net mvc :-)
Thanks,
Jon
ANSWER
Ok guys worked out the issue and its incredibly simple I didn't have the HTML name attribute on the file component of my form:
<input id="MCF" name="MCF" type="file" />
Now this binds to my method signature!
With the first issue, it looks like your action method signature is wrong. Because your fileInput has an ID of MCF, the HttpPostedFileBase parameter should have the same name so that the model binder knows to bind to that action method parameter.
E.g.
public ActionResult Create(Problem problem, AssessmentExtension assessmentExtension, Staff staffMember, HttpPostedFileBase mcf, string[] StaffEmail)
As for the second issue... you could try something like this:
<form method="post" id="ProblemForm" action="<%= Url.Action(ViewContext.RouteData.Values["action"].ToString()) %>" enctype="multipart/form-data">
The current controller will also be in RouteData.Values but if you're after the area, that'll be in RouteData.DataTokens.
HTHs,
Charles
Ok guys worked out the issue and its incredibly simple I didn't have the HTML name attribute on the file component of my form:
<input id="MCFile" name="MCFile" type="file" />
I have changed my method signature to match the name:
public ActionResult Create(Problem problem, AssessmentExtension assessmentExtension, Staff staffMember, HttpPostedFileBase MCFFile, string[] StaffEmail)
Now this binds to my method signature!

ASp.NET MVC: TryUpdateModel doesn't update all properties

I've got the following action:
public ActionResult Create()
{
var entity = new Employee();
TryUpdateModel(entity, new[] { "Person.Name", "Code", "CompanyID" });
if (ModelState.IsValid)
{
var result = Service.MergeEmployee(entity);
return RedirectToAction("List", new { success = true });
}
return View("Edit", new SupplierEmployeeModel() { Employee = entity });
}
What happens is that the property "Person.Name" doesn't get filled by the TryUpdateModel.
This is my form:
<fieldset>
<p>
<label for="Name"><%=Strings.NAME %></label>
<%= Html.TextBox("Person.Name", Model.Employee.Person.Name, new { Class = "text" })%>
<%= Html.ValidationMessage("Name", "*") %>
</p>
<p>
<label for="CompanyID"><%=Strings.SUPPLIER %></label>
<%= Html.DropDownList("CompanyID") %>
<%= Html.ValidationMessage("CompanyID", "*")%>
</p>
<p>
<label for="Code"><%=Strings.CODE %></label>
<%= Html.TextBox("Code", Model.Employee.Code)%>
<%= Html.ValidationMessage("Code", "*") %>
</p>
<p>
<%= Html.Hidden("ID", Model.Employee.ID)%>
</p>
<div id="tabs-DE-actions" class="ui-dialog-buttonpane ui-helper-clearfix" style="display: block;">
<button class="ui-state-default ui-corner-all" type="submit"><%=Strings.SAVE%></button>
</div>
</fieldset>
Any thoughts on why this is happening?
Thanks
Make sure the Person object is initialized in the Employee constructor; if it's null to begin with it is probably not updated properly.
public Employee()
{
Person = new Person();
}
Try this:
TryUpdateModel(entity,"Person", new[] { "Name", "Code", "CompanyID" });
In order to fill in Person.Name, the model binder has to create a new Person. Have you given the model binder enough info to do that? Alternately, try creating the Person yourself before binding.

asp.net mvc - How to find exactly which button was clicked when button names are all identical?

I've got the following code in my aspx file:
<% using (Html.BeginForm())
{
int i = 0;
%>
<% foreach (var item in Model.Educations)
{ %>
<fieldset>
<input type="hidden" name="educations.Index" value="" />
<p>
<label for="PID">
PID:</label>
<%= Html.TextBox("educations["+i+"].PID", item.PID)%>
<%= Html.ValidationMessage("PID", "*")%>
</p>
<p>
<label for="EducationType">
EducationType:</label>
<%= Html.TextBox("educations["+i+"].EducationType", item.EducationType)%>
<%= Html.ValidationMessage("EducationType", "*")%>
</p>
<p>
<label for="SchoolName">
SchoolName:</label>
<%= Html.TextBox("educations["+i+"].SchoolName", item.SchoolName)%>
<%= Html.ValidationMessage("SchoolName", "*")%>
</p>
<p>
<label for="UniversityId">
UniversityId:</label>
<%= Html.TextBox("educations["+i+"].UniversityId", item.UniversityId)%>
<%= Html.ValidationMessage("UniversityId", "*")%>
</p>
<p>
<label for="Department">
Department:</label>
<%= Html.TextBox("educations["+i+"].Department", item.Department)%>
<%= Html.ValidationMessage("Department", "*")%>
</p>
<p>
<label for="Degree">
Degree:</label>
<%= Html.TextBox("educations["+i+"].Degree", String.Format("{0:F}", item.Degree))%>
<%= Html.ValidationMessage("Degree", "*")%>
</p>
<p>
<label for="YearOfGraduation">
YearOfGraduation:</label>
<%= Html.TextBox("educations[" + i + "].YearOfGraduation", String.Format("{0:F}", item.YearOfGraduation))%>
<%= Html.ValidationMessage("YearOfGraduation", "*")%>
</p>
<p>
<label for="ID">
ID:</label>
<%= Html.TextBox("educations[" + i + "].ID", item.ID)%>
<%= Html.ValidationMessage("ID", "*")%>
</p>
<input type="submit" name="silButton" value="Sil"/>
</fieldset>
<%
i++;
} %>
<p>
<input type="submit" name="ekleButton" value="Ekle" />
</p>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>
This way I'm able to dynamically add ("Ekle") more fields if user wants to enter additional education information (most probably from another university or another degree).
This code also give "Sil" button (which means delete), and I want to be able to detect exactly which "Sil" button was pressed and delete that Education entry from my "object" in session.
My action method looks like this:
public ActionResult Step3(string ekleButton, IList<Education> educations, IList<string> silButton)
{
if (educations != null)
{
_person.Educations.Clear();
_person.Educations.AddRange(educations);
}
if (ekleButton != null)
{
_person.Educations.Add(new Education());
}
if (silButton!=null){
//find index and delete it from _person.Edications
}
return View(_person);
}
In this way silButton != null if any of the "silButton" buttons was pressed and I can't detect which button was pressed. Is there a way to find this out?
You could put the index in the name of the button:
<input type="submit" name="silButton<%=i %>" value="Sil" />
And in your action method:
var silButton = Request.Params.AllKeys.FirstOrDefault(key => key.StartsWith("silButton"));
if (!string.IsNullOrEmpty(silButton))
{
var index = int.Parse(silButton.Replace("silButton", string.Empty));
}

Resources