Have an app where I would like to upload an image. I am using byte array for this.
The image is required but when I put that annotation on the variable and try create an image, it gives me the error message when it should have the image there. It also returns that the Model is Invalid.
When I remove the Required, it works but it can also be set as null which is what I don't want.
There doesn't seem to be a lot on the topic on Stack Overflow.
Here is my Model
[Key]
public int InvoiceId { get; set; }
[Required(ErrorMessage = "Company is required")]
public string Company { get; set; }
[Required(ErrorMessage = "Description is required")]
public string Description { get; set; }
[Required(ErrorMessage = "Amount is required")]
public decimal Amount { get; set; }
[Required(ErrorMessage = "Picture of Invoice Required")]
public byte[] PictureOfInvoice { get; set; }
And my controller:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Parish Admin, Priest, Administrator")]
public ActionResult Create([Bind(Include = "InvoiceId,Company,Description,Amount,PictureOfInvoice,DateReceived,ChurchId")] Invoice invoice,HttpPostedFileBase File)
{
if (ModelState.IsValid)
{
if (File != null && File.ContentLength > 0)
{
invoice.PictureOfInvoice = new byte[File.ContentLength];
File.InputStream.Read(invoice.PictureOfInvoice, 0, File.ContentLength);
}
else
{
TempData["Error"] = "Upload an Image";
}
db.Invoices.Add(invoice);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ChurchId = new SelectList(db.Churches, "ChurchId", "Name", invoice.ChurchId);
return View(invoice);
}
My View just in case its something there:
<h2>Add New Invoice</h2>
#if (TempData["Error"] != null)
{
<div style="color:red">#TempData["Error"]</div>
}
#using (Html.BeginForm("Create", "Invoices", FormMethod.Post, new { #class = "form-horizontal", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Company, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Company, new { htmlAttributes = new { #class = "form-control", style = "width:20em;" } })
#Html.ValidationMessageFor(model => model.Company, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Amount, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Amount,new { htmlAttributes = new { #class = "form-control", style = "width:20em;" } })
#Html.ValidationMessageFor(model => model.Amount, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DateReceived, "DateRecieved", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.DateReceived, new { htmlAttributes = new { #class = "form-control", style = "width:20em;" } })
#Html.ValidationMessageFor(model => model.DateReceived, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Description, new { htmlAttributes = new { #class = "form-control", style = "width:20em;" } })
#Html.ValidationMessageFor(model => model.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PictureOfInvoice, "Picture of Invoice", htmlAttributes: new { #class = "control-label col-md-2"})
<div class="col-md-10">
<input type="file" name="File" id="File" style="width: 50%;" />
#Html.ValidationMessageFor(model => model.PictureOfInvoice, "", new { #class = "text-danger" })
<output id="list"></output>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ChurchId, "Church Name", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("ChurchId", null, htmlAttributes: new { #class = "form-control", style = "width:20em;" })
#Html.ValidationMessageFor(model => model.ChurchId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
<u>
#Html.ActionLink("Back to List", "Index")
</u>
</div>
<script src="~/Scripts/jquery.datetimepicker.js"></script>
<script>
$('#DateReceived').datetimepicker({
format: 'd/m/Y',
weeks: true,
disableWeekDays: [0, 1, 3, 4, 5, 6],
timepicker: false,
inline: false
});
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function (theFile) {
return function (e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML = ['<img class="thumb" src="', e.target.result,
'" title="', escape(theFile.name), '"/>'
].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
document.getElementById('File').addEventListener('change', handleFileSelect, false);
</script>
The mixing of concerns here is cause problems. It appears you are trying to use an entity as the model for the view and have it satisfy both UI validation and persistence validation.
Separate the two concerns.
Create a view model specific to the desired behavior of the view.
The model should also include IEnumerable<SelectListItem> ChurchList property to populate the drop down.
public class CreateInvoiceViewModel {
[Required(ErrorMessage = "Company is required")]
public string Company { get; set; }
[Required(ErrorMessage = "Description is required")]
public string Description { get; set; }
[Required(ErrorMessage = "Amount is required")]
public decimal Amount { get; set; }
[Required(ErrorMessage = "Picture of Invoice Required")]
public HttpPostedFileBase File { get; set; }
public int ChurchId { get; set; }
public IEnumerable<SelectListItem> ChurchList { get; set; }
//...other properties
}
and set that as the model of the view
#model CreateInvoiceViewModel
If creating a new invoice there is no id assigned as yet. That means when posting the model as you current have it, the model state cannot be valid as InvoiceId, which is tagged as Required is not provided.
The uploaded file (invoice picture) should also be included in the view model and should use #Html.TextBoxFor(m => m.File, new { type = "file" }) to get client side validation. The model binder will set that property based on whether a matching input was provided.
<div class="form-group">
#Html.LabelFor(model => model.File, "Picture of Invoice", htmlAttributes: new { #class = "control-label col-md-2"})
<div class="col-md-10">
#Html.TextBoxFor(model => model.File, new { type = "file", style = "width: 50%;"})
#Html.ValidationMessageFor(model => model.File, "", new { #class = "text-danger" })
<output id="list"></output>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ChurchId, "Church Name", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.ChurchId, (IEnumerable<SelectListItem>)#Model.ChurchList, htmlAttributes: new { #class = "form-control", style = "width:20em;" })
#Html.ValidationMessageFor(model => model.ChurchId, "", new { #class = "text-danger" })
</div>
</div>
So now on the controller side, [Bind] should be removed as it's not needed when using a view model.
[HttpGet]
[Authorize(Roles = "Parish Admin, Priest, Administrator")]
public ActionResult Create() {
var model = new CreateInvoiceViewModel {
//set default property values as needed
};
model.ChurchList = new SelectList(db.Churches, "ChurchId", "Name");
//...
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Parish Admin, Priest, Administrator")]
public ActionResult Create(CreateInvoiceViewModel model) {
if (ModelState.IsValid) {
var file = model.File;
//copy properties over to entity
var invoice = new Invoice {
Company = model.Company,
Description = model.Description,
Amount = model.Amount,
DateReceived = model.DateReceived,
ChurchId = model.ChurchId,
//create array for file contents
PictureOfInvoice = new byte[file.ContentLength]
};
//populate byte array
file.InputStream.Read(invoice.PictureOfInvoice, 0, file.ContentLength);
db.Invoices.Add(invoice);
db.SaveChanges();
return RedirectToAction("Index");
}
//if we get this far model state is invalid.
//return view with validation errors.
model.ChurchList = new SelectList(db.Churches, "ChurchId", "Name", model.ChurchId);
return View(model);
}
The model state will provide the necessary feedback if the model requirements are not valid. Removing the need for using the temp data and the file check.
You're not using data binding to populate PictureOfInvoice in your model - you're doing it inside your controller's method. But you're only performing that step after confirming that the model is valid, which it cannot be by this logic.
I think you can try just switching the first bits around:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Parish Admin, Priest, Administrator")]
public ActionResult Create(
[Bind(Include = "InvoiceId,Company,Description,Amount,DateReceived,ChurchId")]
Invoice invoice,
HttpPostedFileBase File)
{
if (invoice!=null && File != null && File.ContentLength > 0)
{
invoice.PictureOfInvoice = new byte[File.ContentLength];
File.InputStream.Read(invoice.PictureOfInvoice, 0, File.ContentLength);
}
if (ModelState.IsValid)
{
//Proceed
If that's still not letting the model pass validation then you may have to just continue applying errors as you previously were in the else
Related
I'm trying to insert an image file that a user uploads from a web form into my SQL database so that it shows up on my Index page next to their information. All of the other information sends and shows up on the page, but the photo simply won't save to the database or display on the Index. Could someone help me figure out what I have wrong?
FacultyController.cs
using POS.Datos;
using POS.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.IO ;
namespace POS.Controllers
{
public class FacultyController : Controller
{
FacultyAdmin admin = new FacultyAdmin();
// GET: Faculty
public ActionResult Index()
{
return View(admin.Consultar());
}
[HttpGet]
public ActionResult Nuevo()
{
ViewBag.Meal_Plan = GetPlanesSelect();
admin.Consultar();
return View();
}
[HttpPost]
[ActionName("Guardar")]
public ActionResult NuevoPost(Faculty empleado)
{
if (ModelState.IsValid)
{
Cafeteria_POSEntities context = new Cafeteria_POSEntities();
admin.Consultar();
context.Faculties.Add(empleado);
context.SaveChanges();
ViewBag.mensaje = "Informacion Guardada";
return RedirectToAction("Index");
}
return View(empleado);
}
public ActionResult Guardar() // HTTP GET
{
ViewBag.mensaje = "";
ViewBag.Meal_Plan = GetPlanesSelect();
return View();
}
[HttpGet]
public ActionResult Editar(int id)
{
Cafeteria_POSEntities context = new Cafeteria_POSEntities();
Faculty empleado = context.Faculties.Single(x => x.Employee_ID == id);
ViewBag.Meal_Plan = GetPlanesSelect();
return View(empleado);
}
[HttpPost]
[ActionName("Editar")]
public ActionResult Editar(Faculty empleado)
{
if (ModelState.IsValid)
{
Cafeteria_POSEntities context = new Cafeteria_POSEntities();
context.Entry(empleado).State = EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index");
}
return View(empleado);
}
public IEnumerable<SelectListItem> GetPlanesSelect()
{
using (Cafeteria_POSEntities Context = new Cafeteria_POSEntities())
{
return Context.Plans.Select(plan => new SelectListItem { Value = plan.Plan_Name, Text = plan.Plan_Name }).ToList();
}
}
[HttpGet]
public ActionResult Eliminar(int id)
{
Cafeteria_POSEntities context = new Cafeteria_POSEntities();
Faculty empleado = context.Faculties.Single(x => x.Employee_ID == id);
return View(empleado);
}
[HttpPost]
[ActionName("Eliminar")]
public ActionResult EliminarConfirm(int id)
{
Cafeteria_POSEntities context = new Cafeteria_POSEntities();
Faculty empleado = context.Faculties.Single(x => x.Employee_ID == id);
context.Faculties.Remove(empleado);
context.SaveChanges();
return RedirectToAction("Index");
}
// Saves user-uploaded image to the database //
public string Upload_Image(HttpPostedFileBase image_file)
{
Random r = new Random() ;
String path = "-1" ;
int random = r.Next() ;
if (image_file != null && image_file.ContentLength > 0)
{
string extension = Path.GetExtension(image_file.FileName) ;
if (extension.ToLower().Equals(".jpg") || extension.ToLower().Equals(".jpeg") || extension.ToLower().Equals(".png"))
{
try
{
path = Path.Combine(Server.MapPath("~/Content/Images") , random + Path.GetFileName(image_file.FileName)) ;
image_file.SaveAs(path) ;
path = "~/Content/Images/" + random + Path.GetFileName(image_file.FileName) ;
}
catch (Exception ex)
{
path = "-1" ;
}
}
else
{
Response.Write("<script>alert('Images may only be of the following formats: .jpg , .jpeg , and .png .');</script>") ;
}
}
else
{
Response.Write("<script>alert('Please select an image to upload!');</script>");
path = "-1" ;
}
return path ;
}
}
}
Faculty.cs
namespace POS.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
public partial class Faculty
{
[DisplayName("Employee ID:")]
public int Employee_ID { get; set; }
[DisplayName("Organization Name:")]
public string Organization_Name { get; set; }
[DisplayName("First Name:")]
public string First_Name { get; set; }
[DisplayName("Last Name:")]
public string Last_Name { get; set; }
[DisplayName("Job Title:")]
public string Job_Title { get; set; }
[DisplayName("Email:")]
public string Email { get; set; }
[DisplayName("Photo:")]
public byte[] Photo { get; set; }
[DisplayName("Address:")]
public string Address { get; set; }
[DisplayName("Phone Number:")]
public string Phone_Number { get; set; }
[DisplayName("Meal Plan:")]
public string Meal_Plan { get; set; }
[DisplayName("Meal Plan Status:")]
public bool Meal_Plan_Status { get; set; }
[DisplayName("Plan:")]
public virtual Plan Plan { get; set; }
}
}
Guardar.cshtml
#model POS.Models.Faculty
#{
ViewBag.Title = "Add Faculty Member";
}
<h2>Faculty Member</h2>
<h4>Add a new faculty member</h4>
<!-- Metodo "Nuevo", Controlador "Producto", Accion "HTTP POST" -->
#using (Html.BeginForm("Guardar", "Faculty", FormMethod.Post , new {enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label class="control-label col-md-2" for="Organization_Name">Organization Name</label>
<div class="col-md-10">
#Html.EditorFor(model => model.Organization_Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Organization_Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.First_Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10" for="First_Name">
#Html.EditorFor(model => model.First_Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.First_Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Last_Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Last_Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Last_Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Job_Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Job_Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Job_Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Photo, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Photo, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Photo, "", new { #class = "text-danger" })
<input type="file" id="image_file" name="file"/>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Address, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Address, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Address, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Phone_Number, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Phone_Number, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Phone_Number, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Meal_Plan, "Meal_Plan", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Meal_Plan", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Meal_Plan, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Meal_Plan_Status, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.Meal_Plan_Status)
#Html.ValidationMessageFor(model => model.Meal_Plan_Status, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Guardar" class="btn btn-default" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<font color="green">#ViewBag.mensaje</font>
</div>
</div>
</div>
}
<!--
<h4><b>Personal Information</b></h4>
Name:
Email Address:
<!--
Date of Birth:
-->
<!--
Gender:
Male
Female
Phone Number:
Address (Optional):
<h4><b>Institutional Information</b></h4>
Organization:
Language Institute
Keiser University
<br />
Job Title:
Administrator
Cafeteria Team Member
Cleaning Crew Team Member
Coach
Instructor
I.T. Team Member
Library Team Member
Security Guard
<br />
Meal Plan:
No Plan
A
B
C
Active?
-->
#Html.ActionLink("Return to Faculty Index", "Index")
#section Scripts {
#Scripts.Render("\~/bundles/jqueryval")
}
I've already tried going through this video (https://www.youtube.com/watch?v=-jNWVKoYhaM), but, for some reason, it still doesn't work (though I can now save images to ~/Content/Images and the program actually seems like it wants to pull an image from said file).
You're storing the images to a folder on your server, which is fine. But you also seem to expect the image file to be stored in the database as well. If you're going to store the image files in the file system and not in the database then what you really want in the database is the path to the image file so you can reference that in the HTML. As you are writing the photo to the file system you should also update the database with the path to the file and then in your HTML you can generate an <img> tag to load the file from the file system.
You should update the db during Upload_Image(). Currently it's only saving the image file to the file system.
try
{
path = Path.Combine(Server.MapPath("~/Content/Images") , random + Path.GetFileName(image_file.FileName)) ;
image_file.SaveAs(path) ;
/* SAVE path TO DB HERE */
}
catch (Exception ex)
{
path = "-1" ;
}
}
I have a quick question I am updating my user and there role and my modelstate.isvalid is failing. So the user does not get updated in the database. I don’t have anything [required] that isn’t being entered in a textbox even when I try to enter all fields it still fails. Not sure why.
Here is my data model, my controller action for editing / updating a user and there role and also here is my view with all the controls for inside the view.
Im realy not sure why my modelstate isnt valid i'm not doing anything complicated its just a simple U in CRUD and the action controller isnt validiting the model.
public class UpdateUserViewModel
{
public string UserId { get; set; }
[Display(Name = "User ID")]
public string IdShortened { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[Display(Name = "Username")]
public string UserName { get; set; }
[Display(Name = "Your Name")]
public string Name { get; set; }
[Display(Name = "Phone Number")]
public string PhoneNumber { get; set; }
[DataType(DataType.DateTime),
DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}",
ApplyFormatInEditMode = true)]
[Display(Name = "Birthday")]
public DateTime Birthday { get; set; }
[Display(Name = "Date Created")]
public DateTime? DateCreated { get; set; }
[Required]
[Display(Name = "User Roles")]
public string UserRoles { get; set; }
}
public async Task<ActionResult> EditSuperAdmin(string id)
{
if(id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = await manager.FindByIdAsync(id);
if(user == null)
{
return HttpNotFound();
}
var userRoles = await manager.GetRolesAsync(user.Id);
ViewBag.Roles = new SelectList(
context.Roles.ToList(), "Name", "Name");
//new SelectList(context.Roles.Where(u =>
//!u.Name.Contains("SuperAdmin")).ToList(), "Name", "Name");
return View(new UpdateUserViewModel()
{
UserId = user.Id,
IdShortened = user.Id.Substring(0, 10),
Email = user.Email,
UserName = user.UserName,
Name = user.Name,
PhoneNumber = user.PhoneNumber,
Birthday = user.Birthday,
DateCreated = user.DateCreated,
UserRoles = manager.GetRoles(user.Id).FirstOrDefault()
});
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditSuperAdmin([Bind]UpdateUserViewModel model)
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
if (ModelState.IsValid)
{
var user = manager.FindById(model.UserId);
if (user == null)
{
return HttpNotFound();
}
user.Email = model.Email;
user.UserName = model.UserName;
user.Name = model.Name;
user.PhoneNumber = model.PhoneNumber;
user.Birthday = model.Birthday;
user.DateCreated = Convert.ToDateTime(model.DateCreated);
var roleResult =
manager.AddToRole(user.Id, model.UserRoles);
if (!roleResult.Succeeded)
{
TempData["ErrorRole"] = "Error adding User Role";
return RedirectToAction("Dashboard");
}
manager.Update(user);
context.SaveChanges();
TempData["Success"] = "User Updated Successfully";
return RedirectToAction("GetAllUsers", "SuperAdmin");
}
TempData["Error"] = "User Update Failed";
return RedirectToAction("Dashboard");
} #model MVC_TimeSh.Models.UpdateUserViewModel
#{
ViewData["Title"] = "Update User";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<div class="text-center">
#if (User.IsInRole("SuperAdmin"))
{
<h2>Update Super Administrator</h2>
}
else
{
<h3>Update | Edit User Account</h3>
}
</div>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(m => m.UserId)
<div class="form-group">
#Html.LabelFor(model => model.IdShortened,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.IdShortened, new { htmlAttributes =
new { #class = "form-control", #readonly = "readonly" } })
#Html.ValidationMessageFor(model => model.IdShortened, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name,
new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Email,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email, new { htmlAttributes =
new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Email, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserName,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserName,
new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.UserName, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PhoneNumber,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PhoneNumber,
new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PhoneNumber, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Birthday,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Birthday,
new { htmlAttributes = new { #class = "form-control datepicker" } })
#Html.ValidationMessageFor(model => model.Birthday, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DateCreated,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DateCreated, new { htmlAttributes =
new { #class = "form-control", #readonly = "readonly" } })
#Html.ValidationMessageFor(model => model.DateCreated, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserRoles,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("UserRoles", (SelectList)ViewBag.Roles, "-- SELECT --")
#*new { htmlAttributes = new { #class = "form-control" } })*#
#Html.ValidationMessageFor(model => model.UserRoles, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-success" />
</div>
</div>
</div>
Sorry don't have 50 reputations can't comment.
As Chetan said debug and check the ModelState errors and check if UserRoles property is the issue.
it will be fine if you go with entity framework. Everything works fine there.
I have a scenario where I am editing a model in an ASP.NET MVC5 application and when I submit blank values TryUpdateModel returns false (correctly) but when I return the view with the same model that was passed into TryUpdateModel one of the properties has been updated but others havent' - even though they are all invalid.
Repro:
Load /Machines/Edit?serialNumber=2
Clear Position and Name fields (manually using delete, backspace, or cut)
Click Update button to submit form
The Name property is
updated even though TryUpdateModel returns false.
Is this a string only thing because I don't have a problem with the MachinePosition property being updated no matter what order I provide the includedProperties for https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.tryupdatemodel(v=vs.118).aspx#Anchor_12 in. Has anyone else come across this - it feels like I'm doing something wrong in my code because a side effect like this would surely be documented.
The only reason I noticed this was because I was returning to the main list of machines after attempting to do an invalid update and the noticed that the Name property was being updated for these machines yet when I debugged the code and stepped through it I wasn't hitting when the backing list was being updated/set... very confused.
My model:
public class Machine
{
[Required]
[Range(0, long.MaxValue)]
[Display(Name = "Serial")]
public long SerialNumber { get; set; }
[Required]
[Range(0, 1000)]
[Display(Name = "Position")]
public int MachinePosition { get; set; } = 0;
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
}
My view:
#model MyWebApplication.Machine
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Update #Model.Name</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<!-- Have the serial number shown in a hidden field so that it will be passed through on submit -->
#Html.HiddenFor(model => model.SerialNumber)
<div class="form-group">
#Html.LabelFor(model => model.SerialNumber, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DisplayFor(model => model.SerialNumber, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.MachinePosition, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.MachinePosition, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.MachinePosition, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Update" class="btn btn-default" />
</div>
</div>
</div>
}
My controller:
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditMachine(long? serialNumber)
{
if (serialNumber == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
// Get by serial
Machine machineToUpdate = MachineRepository.Get(serialNumber.Value);
string failureMessage = $"Model validation failed.";
// Model state is valid at this point because we have the serial set
if (ModelState.IsValid)
{
string oldName = machineToUpdate.Name;
int oldPosition = machineToUpdate.MachinePosition;
if (TryUpdateModel(machineToUpdate, "", new string[] { "Name", "MachinePosition" }))
{
Result result = MachineRepository.UpdateMachine(machineToUpdate);
if (result.ResultCode == ResultTypeEnum.Success)
{
// Update the list used by the view to include the new entry
RestoreDatabaseBackup();
// Use PRG pattern to prevent resubmit on page refresh
return RedirectToAction("Edit", new { serialNumber = serialNumber.Value, machineName = $"{oldName}/{machineToUpdate.Name}" });
}
failureMessage = $"There was an error updating the machine: {result.ResultMessage}";
}
}
// Set failure message
ViewBag.UpdateResultMessage = failureMessage;
ViewBag.UpdateSucceeded = false;
// When I get to here the "Name" field has been overwritten with a blank value
return View(machineToUpdate);
}
Despite incorporating all advice I found in other questions and this article
the List vsValues passed to the view is always empty after POST.
View
#model OTS.ParcelOrder
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ParcelOrder</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.otsID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.otsID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.otsID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.parcelID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.parcelID, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.parcelID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.recipientCountry, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.recipientCountry, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.recipientCountry, "", new { #class = "text-danger" })
</div>
</div>
#for (int i = 0; i < Model.vsValues.Count; i++)
{
#Html.Label(Model.ParcelOrder_VSFields.ElementAt(i).VendorSpecifiedInfoField.fieldName,
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.vsValues[i], new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.vsValues[i], "", new { #class = "text-danger" })
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller
// GET: ParcelOrders/Create
public ActionResult Create(int vendorId = 1)
{
ParcelOrder order = new ParcelOrder(vendorId);
return View(order);
}
// POST: ParcelOrders/Create
// Aktivieren Sie zum Schutz vor übermäßigem Senden von Angriffen die spezifischen Eigenschaften, mit denen eine Bindung erfolgen soll. Weitere Informationen
// finden Sie unter http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ParcelOrder parcelOrder)
{
parcelOrder.customerID = User.Identity.GetUserId();
if (ModelState.IsValid)
{
db.ParcelOrder.Add(parcelOrder);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(parcelOrder);
}
public partial class ParcelOrder
{
private Entities db = new Entities();
public List<string> vsValues = new List<string>();
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ParcelOrder()
{
this.ParcelOrder_VSFields = new List<ParcelOrder_VSFields>();
}
public ParcelOrder(int vendorId)
{
this.ParcelOrder_VSFields = new List<ParcelOrder_VSFields>();
var vendorQuery = from vsif in db.VendorSpecifiedInfoField
where vsif.vendorID == vendorId
select vsif;
foreach (var vsif in vendorQuery)
{
vsValues.Add("");
this.ParcelOrder_VSFields.Add(new OTS.ParcelOrder_VSFields
{
vsFieldID = vsif.id,
VendorSpecifiedInfoField = vsif,
value = ""
});
}
}
public string otsID { get; set; }
public string parcelID { get; set; }
public string customerID { get; set; }
public string recipientCountry { get; set; }
public virtual AspNetUsers AspNetUsers { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ParcelOrder_VSFields> ParcelOrder_VSFields { get; set; }
}
}
Note
The values are supposed to be POSTed in the List vsValues and will later be set as properties of ParcelOrder_VSFields inside the controller to avoid POSTing redundant information.
It's because you are posting nothing to no where look at that
#using (Html.BeginForm())
Should rather be like:
#using (Html.BeginForm("Create","ParcelOrders",FormMethod.Post))
Update
Also after that. Your Model looks wrong to me, if you want to pass values to a list i suggest you have a list property of same kind [this property needs to be with in your model ParcelOrder and not virtual]. then within the parameter-less constructor of the class do your foreach. track it within every step you see your issue.
I have the following error staring me in the face.
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.game_04BC2EA428E3397C72CED2755A5A78B93F676BBC970F6B9A8635AD53B08FEBCB', but this dictionary requires a model item of type 'TeamBuildingCompetition.ViewModels.EditGameVM'
I have an ASP.NET NVC 5 intranet application. I created an edit view from a view model to update contents of my database. Content of the database in question is an html content which was posted in by a rich text editor. When I load the edit view, it shows the above error.
Below is my edit view:
#model TeamBuildingCompetition.ViewModels.EditGameVM
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout_new.cshtml";
}
<script>
tinymce.init({ selector: '#description' });
tinymce.init({ selector: '#gameRule' });
</script>
#using (Html.BeginForm("Update", "Game", FormMethod.Post))
{
#Html.AntiForgeryToken()
<section id="middle">
<div class="container">
<div class="form-horizontal">
<div class="center"><h1>Edit Games </h1></div>
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.gameID)
<div class="form-group">
#Html.LabelFor(model => model.gameName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-8">
#Html.EditorFor(model => model.gameName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.gameName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-8">
#Html.EditorFor(model => model.description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.gameRule, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-8">
#Html.EditorFor(model => model.gameRule, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.gameRule, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.gamePicture, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-8">
#Html.TextBoxFor(model => model.gamePicture, new { #type = "file", #name = "gamePicture" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</div>
</section>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Below is the View Model for the Edit View:
namespace TeamBuildingCompetition.ViewModels
{
public class EditGameVM
{
public int gameID { get; set; }
[Required]
[Display(Name = "Game Name")]
public string gameName { get; set; }
[Required][AllowHtml]
[Display(Name = "Description")]
public string description { get; set; }
[Required]
[AllowHtml]
[Display(Name = "Game Rules")]
public string gameRule { get; set; }
[Display(Name = "Game Picture")]
public string gamePicture { get; set; }
}
}
And finally, here's the controller to do the update:
public ActionResult Update(EditGameVM model)
{
try {
game objGame = new game
{
gameID = model.gameID,
gameName = model.gameName,
description = model.description,
gameRule = model.gameRule,
gamePicture = model.gamePicture.ToString()
};
objBs.gameBs.Update(objGame);
TempData["Msg"] = "Created Successfully!";
return RedirectToAction("Edit");
}
catch (DbEntityValidationException dbEx)
{
var sb = new StringBuilder();
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
sb.AppendLine(string.Format("Entity:'{0}' Property: '{1}' Error: '{2}'",
validationErrors.Entry.Entity.GetType().FullName,
validationError.PropertyName,
validationError.ErrorMessage));
}
}
//throw new Exception(string.Format("Failed saving data: '{0}'", sb.ToString()), dbEx);
TempData["Msg"] = sb.ToString();
return RedirectToAction("Edit");
}
}
Here's my Get Method:
public ActionResult Edit(int id = 0)
{
if (id == 0)
{
id = 1;
}
var gameList = objBs.gameBs.GetByID(id);
return View(gameList);
}
I will appreciate all effort to resolving this.
You do not send your model to view, so you caught an error. It is possible to do by this way:
As you use some temporary storage mechanisom like TempData
TempData["Msg"] = objGame;
return RedirectToAction("Edit");
Then just read it in your GET Action method again of your View.
public ActionResult Edit()
{
//Here you should cast your TempData to EditGameVM:
EditGameVM receivedModel=TempData["Msg"] as EditGameVM;
//To take data from TempData["Msg"], you should use receivedModel object:
string gameID=receivedModel.gameID;
string gameName=receivedModel.gameName;
return View(receivedModel);
}
TempData uses Session object behind the scene to store the data. But once the data is read the data is terminated.
I failed to pass the model to my view hence, the above error. After careful examination of my code, I did the following according to https://stackoverflow.com/users/3559349/stephen-muecke advice. All credit goes to this great guy.
public ActionResult Edit(int id = 0)
{
if (id == 0)
{
id = 1;
}
var gameList = objBs.gameBs.GetByID(id);
EditGameVM model = new EditGameVM
{
gameID = id,
gameName = gameList.gameName,
gamePicture = gameList.gamePicture,
gameRule = gameList.gameRule,
description = gameList.description
};
return View(model);
}