My code is as followed and the error message are not displayed:
Index.cshtml
#model WebApp.Models.OrderItems
#using (Html.BeginForm("SaveToDB", "Home", FormMethod.Post, new { #class = "form-group", role = "form" }))
{
#Html.Partial("Information")
}
Partial : Information.cshtml
#model WebApp.Models.OrderItems
<div class="col-lg-4">
<div class="form-group">
<label for="input1" class="col-lg-4 control-label">#Html.LabelFor(model => model.CLInfo.ClientName)</label>
#Html.EditorFor(model => model.CLInfo.ClientName, new { style = "width:250px" })
#Html.ValidationMessageFor(model => model.CLInfo.ClientName)
</div>
</div>
Model :
public class OrderItems
{
public InfoCLInfo{ get; set; }
}
Model : the class for Infos
public class Info
{
[Display(Name = "Client Name")]
[Required]
public string ClientName{ get; set; }
}
The controller
[HttpPost]
[MultipleButton(Name = "action", Argument = "SaveToDB")]
public ActionResult SaveToDB(OrderItems Client)
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
if (ModelState.IsValid)
{
if (_db == null)
_db = new OrderDB();
OrderItems ClientOrig = Session["Clientobj"] as OrderItems;
ClientOrig.CLInfo = Client.CLInfo;
Session["Clientobj"] = null;
}
return RedirectToAction("Index", "Home");
}
[Authorize]
public ActionResult Index (OrderItems Client)
{
int ClientID = Convert.ToInt32(Session["Client"]);
if ClientID == 0)
{
ClientID = 2;
Session["Client"] = ClientID;
}
if (Session["Clientobj"] == null)
{
Client = new OrderItems();
Client.CLOrderID = 123;
Session["Clientobj"] = Client;
}
else
{
Client = Session["Clientobj"] as OrderItems
}
return View(Client);
}
on post the ModelState.IsValid return false which true, but I don't have any message to tell the user where is the error to be fixed.
I tried to add : #Html.ValidationSummary(true) after the BeginForm , but it didn
Any idea please
Thanks
You cannot use RedirectToAction if you want to retain your model state. All errors and what not are kept in the ModelState object, and when you redirect to action it's performing a new get action, which starts fresh with a clean slate.
You need to return the view like you do in the original action.
Related
So, im currently building an application that needs the user model validating, and if the incorrect properties are filled in to the user it will tell them.
I have the data annotations set up, but im not sure how i relay the error message back to the user?
I have this set up so far on my model and view.
Model
public class DatabaseModel
{
[Required(ErrorMessage = ("A first name is required"))]
public string FirstName { get; set; }
[Required(ErrorMessage = ("A last name is required"))]
public string LastName { get; set; }
[Required(ErrorMessage = ("A valid role is required"))]
public string Role { get; set; }
// TODO - Validate rank to only b 1 - 10
//
[Range(1,10, ErrorMessage = ("A rank between 1 and 10 is required"))]
public int Rank { get; set; }
}
And View
#model RoleCreatorAndEditor.Models.DatabaseModel
#{
ViewData["Title"] = "Index";
}
<h2>User Information</h2>
<p>This is your user information!</p>
#using (Html.BeginForm("Index", "Home", FormMethod.Post)) {
#Html.Label("First Name")
<br>
#Html.TextBoxFor(m => m.FirstName)
<br>
#Html.Label("Last Name")
<br>
#Html.TextBoxFor(m=>m.LastName)
<br>
#Html.Label("Role")
<br>
#Html.TextBoxFor(m => m.Role)
<br>
#Html.Label("Rank")
<br>
#Html.TextBoxFor(m => m.Rank)
<br><br>
<input type="submit" value="Save">
}
My Controller
public class HomeController : Controller
{
// GET: Home
[HttpGet]
public ActionResult Index()
{
DatabaseModel model = new DatabaseModel();
return View(model);
}
[HttpPost]
public ActionResult Index(DatabaseModel model)
{
if (ModelState.IsValid)
{
ListToDatatable convert = new ListToDatatable();
DataTable user = convert.Convert(model);
DatabaseRepository dbRepo = new DatabaseRepository();
dbRepo.Upload(user);
}
return View();
}
}
I believe the model needs to be passed back to the view in order to display the error message, and although i have read through the documentation on asp.net i cannot understand how they just add the error message and the form knows how to display the errors to the user.
I am extremely confused.
You need to use ModelState.IsValid in your Controller and also #Html.ValidationMessageFor(model => model.FirstName) in your view:
public ActionResult Index(ViewModel _Model)
{
// Checking whether the Form posted is valid one.
if(ModelState.IsValid)
{
// your model is valid here.
// perform any actions you need to, like database actions,
// and/or redirecting to other controllers and actions.
}
else
{
// redirect to same action
return View(_Model);
}
}
For your example:
#model RoleCreatorAndEditor.Models.DatabaseModel
#{
ViewData["Title"] = "Index";
}
<h2>User Information</h2>
<p>This is your user information!</p>
#using (Html.BeginForm("Index", "Home", FormMethod.Post)) {
#Html.LabelFor(m=>m.FirstName)
<br>
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
<br>
#Html.LabelFor(m=>m.LastName)
<br>
#Html.TextBoxFor(m=>m.LastName)
#Html.ValidationMessageFor(model => model.LastName, "", new { #class = "text-danger" })
. . .
<input type="submit" value="Save">
}
Controller:
[HttpPost]
public ActionResult Index(DatabaseModel model)
{
if (ModelState.IsValid)
{
ListToDatatable convert = new ListToDatatable();
DataTable user = convert.Convert(model);
DatabaseRepository dbRepo = new DatabaseRepository();
dbRepo.Upload(user);
}
return View(model);
}
I know this might be a lot of code to look at it, but it seemed like it was necessary to share it. Thanks in advance for reading!
I am building an application starting with the ASP.NET MVC 5 default template. I want to add a checkbox list of Identity's ApplicationRoles to the Register action of the Account controller.
So, rather than just collect the first and last names, email, phone number, etc., I also want to supply a checkbox list of roles in the database.
I've added this to the RegisterViewModel (in AccountViewModels.cs):
[Required]
[Display(Name = "Roles List")]
public IEnumerable<SelectListItem> RolesList { get; set; }
I changed the Account controller's HttpGet Register action from this:
// GET: /Account/Register
public ActionResult Register()
{
return View();
}
to this:
// GET: /Account/Register
[HttpGet]
public ActionResult Register()
{
//Populate the roles checkbox list for the view
RegisterViewModel model = new RegisterViewModel
{
RolesList = RoleManager.Roles.OrderBy(r => r.Name).ToList().Select(r => new SelectListItem()
{
Text = r.Name,
Value = r.Name,
Disabled = (r.Name == "Admin" && !User.IsInRole("Admin"))
})
};
return View(model);
}
Finally, I updated the Account controller's HttpPost Register action to this:
// POST: /Account/Register
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model, params string[] rolesSelectedOnView)
{
if (ModelState.IsValid)
{
rolesSelectedOnView = rolesSelectedOnView ?? new string[] { };
var user = new ApplicationUser { FirstName = model.FirstName, LastName = model.LastName, PhoneNumber = model.PhoneNumber, UserName = model.Email, Email = model.Email};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var rolesAddResult = await UserManager.AddToRolesAsync(user.Id, rolesSelectedOnView.ToString());
if (!rolesAddResult.Succeeded)
{
ModelState.AddModelError("", rolesAddResult.Errors.First());
AddErrors(rolesAddResult);
return View(model);
}
string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account");
ViewBag.Message = "A confirmation email has been sent to the address you specified. Please have "
+ "the person check their email and confirm their account. The account must be confirmed "
+ "from the confirmation email before they can log in.";
return View("Info");
//return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
The Register view looks (in part) like this:
#model MngiReferrals.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
...removed...
<div class="form-group">
#Html.Label("Roles", new { #class = "col-md-offset-2 col-md-10" })
<span class="col-md-offset-2 col-md-10">
#foreach (var item in Model.RolesList)
{
<input type="checkbox" name="RolesList" value="#item.Value" class="checkbox-inline" />
#Html.Label(item.Value, new {#class = "control-label"})
<br />
}
</span>
</div>
This allows the Register view to render with the normal fields and the list of roles in the database. However, when I submit the form, it doesn't try to validate the roles list (even though I've marked it as [Required] in the view model. Furthermore, it returns me to the Register form with the fields filled in, but then the checkbox list of roles is no longer on the form.
Finally, if I try to submit the form again, it returns this error from the view:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Line 51: #Html.Label("Roles", new { #class = "col-md-offset-2 col-md-10" })
Line 52: <span class="col-md-offset-2 col-md-10">
Line 53: #foreach (var item in Model.RolesList)
Line 54: {
Line 55: <input type="checkbox" name="RolesList" value="#item.Value" class="checkbox-inline" />
After making these changes, the user is no longer registered in the database, so I'm not sure I'm even ever making it to the HttpPost Register action.
I would appreciate it if someone could help me fill in the blanks on this problem. Thank you in advance!
UPDATE #1
I updated my code based on a previous answer by #StephenMuecke (see his comment below for the link). I am close, but it looks like I am not correctly capturing the selected checkbox values.
Here is what this looks like now.
RegisterViewModel (in AccountViewModels.cs):
public class RegisterViewModel
{
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
...more properties...
[Required]
[Display(Name = "Roles List")]
public IEnumerable<SelectListItem> RolesList { get; set; }
public RegisterViewModel()
{
RolesList = new List<ApplicationRoleRegisterViewModel>();
}
}
ApplicationRoleRegisterViewModel (new View Model for the ApplicationRoles)
public class ApplicationRoleRegisterViewModel
{
[Required]
public string Name { get; set; }
public bool IsSelected { get; set; }
public bool IsDisabled { get; set; }
}
HttpGet Account Register action:
// GET: /Account/Register
[HttpGet]
public ActionResult Register()
{
//Populate the roles checkbox list for the view
var model = new RegisterViewModel { RolesList = new List<ApplicationRoleRegisterViewModel>() };
var roles = RoleManager.Roles.OrderBy(r => r.Name);
foreach (var role in roles)
{
var roleVm = new ApplicationRoleRegisterViewModel
{
Name = role.Name,
IsSelected = false, // Since this is for a user that does not yet exist, this would initially be deselected.
IsDisabled = role.Name == "Admin" && !User.IsInRole("Admin")
};
model.RolesList.Add(roleVm);
};
return View(model);
}
HttpPost Account Register action:
// POST: /Account/Register
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { FirstName = model.FirstName, LastName = model.LastName, PhoneNumber = model.PhoneNumber, UserName = model.Email, Email = model.Email};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
//populate the roles checkbox list
var rolesSelectedOnView = model.RolesList.ToList();
foreach (var role in rolesSelectedOnView)
{
var roleVm = new ApplicationRoleRegisterViewModel
{
Name = role.Name,
IsSelected = role.IsSelected,
IsDisabled = role.IsDisabled
};
model.RolesList.Add(roleVm);
};
var rolesAddResult = await UserManager.AddToRolesAsync(user.Id, rolesSelectedOnView.Select(r => r.Name).ToArray());
if (!rolesAddResult.Succeeded)
{
ModelState.AddModelError("", rolesAddResult.Errors.First());
AddErrors(rolesAddResult);
return View(model);
}
string callbackUrl = await SendEmailConfirmationTokenAsync(user.Id, "Confirm your account");
// Uncomment to debug locally
// TempData["ViewBagLink"] = callbackUrl;
ViewBag.Message = "A confirmation email has been sent to the address you specified. Please have "
+ "the person check their email and confirm their account. The account must be confirmed "
+ "from the confirmation email before they can log in.";
return View("Info");
//return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Register View (uses RegisterViewModel):
<div class="form-group">
#Html.Label("Roles", new { #class = "col-md-offset-2 col-md-10" })
<span class="col-md-offset-2 col-md-10">
#for (var i = 0; i < Model.RolesList.Count; i++)
{
#Html.HiddenFor(m => m.RolesList[i].Name)
#Html.CheckBoxFor(m => m.RolesList[i].IsSelected)
#Html.LabelFor(m => m.RolesList[i].IsSelected, Model.RolesList[i].Name)
<br />
}
</span>
</div>
my LogIn is partial view. i pass a model that contain some fields of tbl_profile to partial view and fill it and then i pass filled model to a actionresult in [HttpPost] part and ...
but now i'm trouble in [HttpGet] part . i get this error on this line of cod " *#Html.Action("LogOn","Account")"*.
my code :
[HttpGet]
public ActionResult LogOn(string returnUrl)
{
using (var db = new MyContext())
{
var AllFeatureToLog = db.tbl_profile.Select(u => new UsersClass.LogOn { username = u.username, password_User = u.password_User }).ToList();
return PartialView(AllFeatureToLog);
}
}
class:
public class UsersClass
{
public class LogOn
{
public string username { get; set; }
public string password_User { get; set; }
}
}
LogOn.cshtml:
#model MyProject.Models.UsersClass.LogOn
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<form class="signin-form">
#Html.TextBoxFor(m => m.username, new { #id = "username", #class = "input-block- level", #placeholder = "* enter username" })
#Html.TextBoxFor(m => m.password_User, new { #id = "password", #class = "input-block-level", #placeholder = "* enter pass" })
#Html.ValidationMessage("LoginError")
<label class="checkbox">
<input type="checkbox">remember me</label>
<button class="btn btn-medium btn-general input-block-level" type="submit"> enter</button>
</form>
}
error:
Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'
Use this instead ::
#{ Html.RenderAction("LogOn","Account"); }
This will fix your issue.
You sending List:
var AllFeatureToLog = db.tbl_profile.Select(u => new UsersClass.LogOn { username = u.username, password_User = u.password_User }).ToList();
return PartialView(AllFeatureToLog);
But your View expectiong only one model:
#model MyProject.Models.UsersClass.LogOn
Change: your ActionResult on sending one: var AllFeatureToLog = db.tbl_profile.Select(u => new UsersClass.LogOn { username = u.username, password_User = u.password_User }).Fist();
or View for getting List: #model IENumerable<MyProject.Models.UsersClass.LogOn>
I have feedback form on my mvc site, it looks like
I created model for my form
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ComponentTrading.Web.Models
{
public class FeedbackForm
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Message { get; set; }
}
}
I created view for my form
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "contact-form" }))
{
<fieldset>
#Html.TextBoxFor(model => model.Name, new { #Value = "Name" })
#Html.TextBoxFor(model => model.Email, new { #Value = "E-mail" })
#Html.TextBoxFor(model => model.Phone, new { #Value = "Phone" })
#Html.TextAreaFor(model => model.Message, new { #class = "img-shadow"})
<input class="form-button" data-type="reset" value="Clear" />
<input class="form-button" data-type="submit" type="submit" value="Send" />
}
and now i try to do a sending a letter to email, but it doesn work, when I push "send-button" it happens nothing and I dont get email
my controller
[HttpGet]
public ActionResult Contacts()
{
FeedbackForm temp = new FeedbackForm();
temp.Message = "Message";
return View(temp);
}
[HttpPost]
public ActionResult Contacts(FeedbackForm Model)
{
string Text = "<html> <head> </head>" +
" <body style= \" font-size:12px; font-family: Arial\">"+
Model.Message+
"</body></html>";
SendEmail("mironny#inbox.ru", Text);
FeedbackForm temp = new FeedbackForm();
return View(temp);
}
public static bool SendEmail(string SentTo, string Text)
{
MailMessage msg = new MailMessage();
msg.From = new MailAddress("Test#mail.ru");
msg.To.Add(SentTo);
msg.Subject = "Password";
msg.Body = Text;
msg.Priority = MailPriority.High;
msg.IsBodyHtml = true;
SmtpClient client = new SmtpClient("smtp.mail.ru", 25);
client.UseDefaultCredentials = false;
client.EnableSsl = false;
client.Credentials = new NetworkCredential("TestLogin", "TestPassword");
client.DeliveryMethod = SmtpDeliveryMethod.Network;
//client.EnableSsl = true;
try
{
client.Send(msg);
}
catch (Exception)
{
return false;
}
return true;
}
what's wrong?
Use
// if you dont pass any parameter
// BeginForm posted to the action that
// has name as view name.
// so no need to write any parameters
#using (Html.BeginForm())
{
...
<input type="submit" value="Send">
}
OR
#using (Html.BeginForm("Contacts", "SomeController", FormMethod.Post, new { id = "contact-form" }))
{
...
<input type="submit" value="Send">
}
You have a few question about mvc and there is more important thing of them is incorrect overload methods. My suggestion, first, you should learn html-helpers overload methods. And MVC model binding strategies...
In my application I have associated my UserId to a table in my database. I need that when I create a new item I can choose the user name from a dropdownlist. And 'possible to do this with the element viewbag?
#Html.EditorFor(model => model.UserId)
I use default membership provider so I can't use Entity Framework for this problem
EDIT
EDIT 2
This is my action create:
[HttpPost]
public ActionResult Create(Employe employe)
{
var users = Roles.GetUsersInRole("Admin");
SelectList list = new SelectList(users);
ViewBag.Users = list;
if (ModelState.IsValid)
{
**employe.EmployeID = users;**
db.Employes.Add(employe);
db.SaveChanges();
}
This does not work. The error is:
Cannot implicitly convert type 'string[]' to 'string'
My model for Employee
public class Employee
{
[Key]
public int EmployeID { get; set; }
public Guid UserId { get; set; }
public string Name { get; set; }
[ForeignKey("UserId")]
public virtual MembershipUser User
{
get
{
return Membership.GetUser(this.Name); //Changed this to Name
}
}
}
}
View:
#Html.DropDownList("Users", ViewBag.Users as SelectList);
My result in UserId field isn't a UserId but this 000000-000000-0000000-00000
How to set a list of users as a SelectItem in the ViewBack
Yes, you should be able to do this by passing your collection to the ViewBag and then create you dropdown from it:
In your controller
var users = Roles.GetUsersInRole("Admin");
SelectList list = new SelectList(users);
ViewBag.Users = list;
In your View (If you're using Razor)
#Html.DropDownList("Users", ViewBag.Users as SelectList);
Read more about SelectListItem here:
http://msdn.microsoft.com/en-us/library/system.web.mvc.selectlistitem.aspx
Also check out:
How can I get this ASP.NET MVC SelectList to work?
Problem with ASP.Net MVC SelectLIst and List<SelectListItems>
Question changed to something more. Here is my idea to solve the issue:
Controller:
public ActionResult Mirko() {
List<SelectListItem> items = new List<SelectListItem>();
foreach (string userName in Roles.GetUsersInRole("Admin")) {
var user = Membership.GetUser(userName);
SelectListItem li = new SelectListItem {
Value = user.ProviderUserKey.ToString(),
Text = user.UserName,
};
items.Add(li);
}
items.Add(new SelectListItem { Text = "Please Select...", Value = "na" , Selected = true});
ViewBag.Users = items;
return View();
}
[HttpPost]
public ActionResult Mirko(Employee employee) {
if(IsValideEmployee(employee)) {
/*Only used to show that user was retrieved*/
TempData["message"] = "Saved Employee";
TempData["user"] = employee.User;
/* employeeRepository.Save(employee) */
/* Redirect to where you want to go */
return RedirectToAction("Mirko", "Home");
}
return View(employee);
}
private bool IsValideEmployee(Employee emp) {
if (emp.Name == "na")
ModelState.AddModelError("UserId", "You must select a user!");
/*Do some validation here*/
//ModelState.Add("Name", "You must set the user name!")
return ModelState.IsValid;
}
View
#model StackOverFlowExample.Models.Employee
#{
MembershipUser user = null;
ViewBag.Title = "Mirko Example";
var users = ViewBag.Users as IEnumerable<SelectListItem>;
}
#if (TempData["message"] != null) {
user = TempData["user"] as MembershipUser;
<h3>#TempData["message"]</h3>
<div>
<span>You selected #user.UserName</span>
<ul>
<li>Email: #user.Email</li>
<li>Last Logged In: #user.LastLoginDate.ToString("d")</li>
<li>Online: #user.IsOnline</li>
</ul>
</div>
}
#using (#Html.BeginForm()) {
<label for="UserId">Associate Employee To User:</label>
#Html.DropDownListFor(m => m.UserId, #users)
#Html.HiddenFor(m => m.Name)
<input type="submit" value="Save" id="save-employee"/>
}
<div id="status" style="display:none;"></div>
<script type="text/javascript">
$(document).ready(function () {
$("#UserId").change(function () {
//Set value of name
$("#Name").val($(this).children("option:selected").text());
});
$("#save-employee").click(function (e) {
var value = $("#Name").val();
if (value == "" || value == "na") {
e.preventDefault();
$("#status").html("<h3>You must select a user!</h3>").toggle();
}
});
});
</script>