My issue is when I create a TextBox, it shows an image name but on type file it does not show its name and no file is chosen in it.
I want to show image name instead of "No file chosen".
public ActionResult userprofile(int? id)
{
var user = db.Personaltables.Find(id);
return View(user);
}
[HttpPost]
public ActionResult userprofile(Personaltable u, HttpPostedFileBase file, HttpPostedFileBase file1)
{
db.Entry(u).State = System.Data.Entity.EntityState.Modified;
if (file != null)
{
PersonaltableEntities db = new PersonaltableEntities();
string ImageName = System.IO.Path.GetFileName(file.FileName);
string physicalPath = Server.MapPath("~/Images/" + ImageName);
// save image in folder
file.SaveAs(physicalPath);
u.AttachPicture = ImageName;
}
using (PersonaltableEntities entity = new PersonaltableEntities())
{
var t = new Personaltable() // make variable of table
{
AttachPicture = u.AttachPicture,
};
db.SaveChanges();
}
return RedirectToAction("Index");
}
In Razor view:
#using (Html.BeginForm("userprofile", "personal", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
<label class="label other">
Attach Picture
</label>
<div class="col-md-10">
#Html.EditorFor(model => model.AttachPicture, new { htmlAttributes = new { #class = "form-control", #readonly = "readonly" } })
<input type="file" name="file" id="file" style="width: 100%;" data-val="true" data-val-required="File is required" /> <br />
#Html.ValidationMessageFor(model => model.AttachPicture, "", new { #class = "text-danger" })
</div>
</div>
}
Image name is stored in database and show in text box but in file type is empty
No file is chosen - why it is not stored in it?
Related
I have a scenario where I have a form where I would like administrators to modify their exam / survey details, I am trying to update my database table with the following code.
However the code does not save my changes for the "if" part in my controller, and does not throw any error, and will just redirect me to the next page which is "EditExam2".
I am trying to update the "InformationSheetText" and "InformationConsentForm" fields.
I know the query works as the the "else" part of my code in my controller works when adding a new row into the database.
My View
#model
AppXamApplication.Models
InformationSheetViewModel
#{
ViewBag.Title = "InformationSheet";
}
<!DOCTYPE html>
<html>
<body>
<h2>InformationSheet</h2>
<h3>Survey ID: #ViewBag.CurrentExamID</h3>
#using (Html.BeginForm("InformationSheet", "ExamAdmin", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<h4>Create Information and Consent Sheet.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.ImageURL, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
<input type="file" name="ImageFile" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.InformationSheetText, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.EditorFor(m => m.InformationSheetText, new { #class = "form-control", #rows = 4, #style = "resize: none;" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
#Html.CheckBoxFor(m => m.Check_InformationSheet, new { #disabled = "disabled", #checked = true })
#Html.LabelFor(m => m.Check_InformationSheet, new { })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.InformationConsentForm, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.EditorFor(m => m.InformationConsentForm, new { #class = "form-control", #rows = 4, #style = "resize: none;" })
</div>
</div>
<div class="form-group">
<div class="col-md-10">
#Html.CheckBoxFor(m => m.Check_InformationConsentForm1, new { #disabled = "disabled", #checked = true })
#Html.LabelFor(m => m.Check_InformationConsentForm1, new { })
</div>
<div class="col-md-10">
#Html.CheckBoxFor(m => m.Check_InformationConsentForm2, new { #disabled = "disabled", #checked = true })
#Html.LabelFor(m => m.Check_InformationConsentForm2, new { })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Create Exam" />
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
My model
public class InformationSheetViewModel
{
public string ExamID { get; set; }
[Display(Name = "Choose Image To Display")]
public string ImageURL { get; set; }
[Display(Name = "Enter your Information Sheet")]
public string InformationSheetText { get; set; }
[Display(Name = "Enter your Consent Form")]
public string InformationConsentForm { get; set; }
public HttpPostedFileBase ImageFile { get; set; }
[Display(Name = "I had read and understood the information sheet")]
public bool Check_InformationSheet { get; set; }
[Display(Name = "I consent and agree to the information consent form")]
public bool Check_InformationConsentForm1 { get; set; }
[Display(Name = "I have read, agree and consent to the information and conditions")]
public bool Check_InformationConsentForm2 { get; set; }
}
My Controller
[HttpGet]
public ActionResult InformationSheet(string id)
{
if (ModelState.IsValid)
{
ViewBag.CurrentExamID = id;
using (var ctx = new AppXamApplicationEntities())
{
var query = ctx.InformationConsentAndSheets.Where(x => x.ExamID.Equals(id)).Select(x => new InformationSheetViewModel()
{
ExamID = id,
InformationSheetText = x.InformationSheetText,
InformationConsentForm = x.InformationSheetText
}).FirstOrDefault();
return View(query);
}
}
return View();
}
[HttpPost]
[Authorize(Roles = "ExamAdmin")]
[ValidateAntiForgeryToken]
public ActionResult InformationSheet(string id, InformationSheetViewModel model)
{
using (var ctx = new AppXamApplicationEntities())
{
InformationConsentAndSheet query = ctx.InformationConsentAndSheets.Where(x => x.ExamID.Equals(id)).FirstOrDefault();
if (query != null)
{
//To insert picture into database as well as folder
string fileName = Path.GetFileNameWithoutExtension(model.ImageFile.FileName);
string extension = Path.GetExtension(model.ImageFile.FileName);
fileName = fileName + DateTime.Now.ToString("yymmssfff") + extension;
model.ImageURL = "~/Image/" + fileName;
fileName = Path.Combine(Server.MapPath("~/Image/"), fileName);
model.ImageFile.SaveAs(fileName);
query = new InformationConsentAndSheet()
{
ExamID = id,
ImageURL = model.ImageURL,
InformationSheetText = model.InformationSheetText,
InformationConsentForm = model.InformationConsentForm
};
ctx.SaveChanges();
}
else
{
//To insert picture into database as well as folder
string fileName = Path.GetFileNameWithoutExtension(model.ImageFile.FileName);
string extension = Path.GetExtension(model.ImageFile.FileName);
fileName = fileName + DateTime.Now.ToString("yymmssfff") + extension;
model.ImageURL = "~/Image/" + fileName;
fileName = Path.Combine(Server.MapPath("~/Image/"), fileName);
model.ImageFile.SaveAs(fileName);
query = new InformationConsentAndSheet()
{
ExamID = id,
ImageURL = model.ImageURL,
InformationConsentForm = model.InformationConsentForm,
InformationSheetText = model.InformationSheetText
};
ctx.InformationConsentAndSheets.Add(query);
ctx.SaveChanges();
}
return RedirectToAction("EditExam2");
}
}
I am very perplexed to what is wrong with my code, any form of help will be very appreciated as I am extremely new to MVC in general.
First of all you need to send your Id of survey when you want to edit. It can be done easly by route parameters in your form.
#using (Html.BeginForm("InformationSheet", "ExamAdmin", new { id = ViewBag.CurrentExamID }, FormMethod.Post, new { enctype = "multipart/form-data" }))
Your code for edit existing item is a little bit wrong. You need to, well, modify existing InformationConsentAndSheet and not creating new.
InformationConsentAndSheet query = ctx.InformationConsentAndSheets.Where(x => x.ExamID.Equals(id)).FirstOrDefault();
if (query != null)
{
// work with files
query.ExamID = id;
query.ImageURL = model.ImageURL;
query.InformationSheetText = model.InformationSheetText;
query.InformationConsentForm = model.InformationConsentForm;
ctx.Entry(query).State = EntityState.Modified;
ctx.SaveChanges();
}
Before submiting changes you need to specify that query have been edited and needs to be saved.
Hope its helps.
I have a create function to insert view data to database. The view has a upload file textbox along with other textboxes. How do I bind form data and insert the uploaded file in bytes to a table?
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.LabelFor(model => model.Princial_name)
#Html.EditorFor(model => model.Princial_name)
#Html.ValidationMessageFor(model => model.Princial_name)
#Html.LabelFor(model => model.p_campus)
#Html.EditorFor(model => model.p_campus)
#Html.ValidationMessageFor(model => model.p_campus)
#Html.LabelFor(model => model.filepath)
<input type="file" name="postedFile" />
<input type="submit" value="Submit" class="btn btn-default" />
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "id,Princial_name,p_campus,filepath,filedata")] grant grant)
{
HttpPostedFileBase postedFile;
byte[] bytes;
using (BinaryReader br = new BinaryReader(postedFile.InputStream))
{
bytes = br.ReadBytes(postedFile.ContentLength);
}
if (ModelState.IsValid)
{
grant.id = Guid.NewGuid();
db.Entry(grant).State = EntityState.Modified;
//add filepath
db.Entry(grant).Property("filepath").CurrentValue = Path.GetFileName(postedFile.FileName);
db.Entry(grant).Property("filedata").CurrentValue = bytes;
db.grant.Add(grant);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(grant);
}
The controller cannot insert both form data and upload file data to database. How do I do it? Thanks.
put a second parameter
Create([Bind(Include = "id,Princial_name,p_campus,filepath,filedata")] grant grant, HttpPostedFileBase postedFile)
My first model
public class article
{
public int id { set; get; }
public string title { set; get; }
public string bodyofarticle { set; get; }
public ICollection <image> images { set; get; }
}
The second model which I use to store the images URL in the database
public class image
{
public int id { set; get; }
public int articleid { set; get; }
public string url{ set; get; }
}
Form to enter the values its okay to enter the
article model but when I put any image it did not insert into the database
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>article</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.bodyofarticle, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.bodyofarticle, new { htmlAttributes = new { #class = "form-control" }, cols = 60, rows = 10 } )
#Html.ValidationMessageFor(model => model.bodyofarticle, "", new { #class = "text-danger" })
</div>
<input type="file" multiple id="file" name="file" />
</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>
}
When I look at the break point I see that files are empty and I have tried many ways but it's still empty
public ActionResult Create([Bind(Include = "id,title,bodyofarticle")] article article , HttpPostedFileBase files)
{
if (ModelState.IsValid)
{
if (files != null && files.ContentLength >0 )
{
foreach (string file in Request.Files)
{
var v = Request.Files[file];
var fileName = Path.GetFileName(files.FileName);
var path = Path.Combine(Server.MapPath("~/images/"), fileName);
files.SaveAs(path);
image imag = new image();
imag.url = Url.Content("~/images/" + fileName);
article.images.Add(imag);
}
}
db.articles.Add(article);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(article);
}
Try this in the view. You will need to post the file from view.
#using (Html.BeginForm("Create", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
Hope you used the command add-migrations before using the update-database command.
//it was at the view
#using (Html.BeginForm("Create", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
//thnx vikrim and jim
I am uploading file using asp.net mvc with file upload required but unable to upload file using this. How to make file upload required with validation using ASP.NET MVC?
Here is my Model class code.
public class Slider
{
public int SliderId { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string FileURL { get; set; }
}
Here is my Create Controller:
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Create([Bind(Include = "SliderId,Title,FileURL")] HttpPostedFileBase file, Slider slider)
{
if (ModelState.IsValid)
{
if (file != null)
{
string fil = System.IO.Path.GetFileName(file.FileName);
string path = System.IO.Path.Combine(Server.MapPath("~/Content/Uploads/Slider/"), fil);
file.SaveAs(path);
slider.FileURL = "/Content/Uploads/Slider/" + file.FileName;
}
db.Sliders.Add(slider);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(slider);
}
Here is my View:
#model Test.Models.Slider
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("Create", "SliderManager", FormMethod.Post, new { enctype = "multipart/Form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h2>Create</h2>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title,"Title*", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-2">
<label for="file">Upload Image for Slide*:</label>
</div>
<div class="col-md-10">
<input type="file" name="file" id="file" style="width:50%" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Changes to make
1st model
public class Slider
{
public int SliderId { get; set; }
[Required]
public string Title { get; set; }
public string FileURL { get; set; }
}
Removed required on file Url as this is not coming from user but you should be populating it
2nd Upload action
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Create(HttpPostedFileBase file, Slider slider)
{
//Add validation if file is not present and fail model
if (file == null)
{
ModelState.AddModelError("FileURL", "Please upload file");
}
if (ModelState.IsValid)
{
if (file != null)
{
string fil = System.IO.Path.GetFileName(file.FileName);
string path = System.IO.Path.Combine(Server.MapPath("~/Content/Uploads/Slider/"), fil);
file.SaveAs(path);
slider.FileURL = "/Content/Uploads/Slider/" + file.FileName;
}
//db.Sliders.Add(slider);
//db.SaveChanges();
return RedirectToAction("Index");
}
return View("~/Views/Home/Index.cshtml", slider);
//return View(slider);
}
Also I am not sure why you have specified additional bindings, but I guess you had some reason for that
3rd the view
#using (Html.BeginForm("Create", "Home", FormMethod.Post, new { enctype = "multipart/Form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h2>Create</h2>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Title, "Title*", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-2">
<label for="file">Upload Image for Slide*:</label>
</div>
<div class="col-md-10">
<input type="file" name="file" id="file" style="width:50%" />
#Html.ValidationMessageFor(x=>x.FileURL)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
I have added validation message. This validation message of course can have its own property and I would modify it so it fits with your business logic.
<input type="file" name="file" id="file" style="width:50%" />
#Html.ValidationMessageFor(x=>x.FileURL)
I think the solution from this tutorial is better because it doesn't need an extra property:
https://www.aspsnippets.com/Articles/Fileupload-validation-using-Model-Data-Annotations-in-ASPNet-MVC.aspx
Model:
public class FileModel
{
[Required(ErrorMessage = "Please select file.")]
public HttpPostedFileBase PostedFile { get; set; }
}
View:
#model FileUpload_Validation_MVC.Models.FileModel
#{
Layout = null;
}
<div>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<span>Select File:</span>
#Html.TextBoxFor(m => m.PostedFile, new { type = "file"})
<br/>
#Html.ValidationMessageFor(m => m.PostedFile, "", new { #class = "error" })
<hr/>
<input type="submit" value="Upload"/>
}
</div>
I have the following model:
public class Photo
{
public int PhotoId { get; set; }
public byte[] ImageData { get; set; }
public DateTime DateUploaded { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
}
I would like the user to be able to enter the details for the photo then post the model the the controller. My controller action is as follows:
[HttpPost]
public ActionResult Create(WilhanWebsite.DomainClasses.Photo photo)
{
if (ModelState.IsValid)
{
photo.DateUploaded = DateTime.Now;
_context.Photos.Add(photo);
_context.SaveChanges();
return RedirectToAction("Index");
}
//we only get here if there was a problem
return View(photo);
}
My view is as follows:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Photo</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.ImageData, new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" name="uploadImages" class="input-files" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DateUploaded, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.DateUploaded)
#Html.ValidationMessageFor(model => model.DateUploaded)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Description, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IsActive, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.IsActive)
#Html.ValidationMessageFor(model => model.IsActive)
</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>
}
The view is displayed ok and allows the user to select a file from their local disk and enter the other model details.
My problem is that although the model is posted to the controller ok, the Description, Date and IsActive flags are populated ok - the Image data is null.
Could anyone please let me know what I need to change so that the byte array for the photo is included in the model posted to the controller?
The file input in your view has a name uploadImages. I can't see a property with this name in your view model. You seem to have some ImageData property which is a byte array, but there doesn't seem to be a corresponding input field with this name in your view.
This explains why you get null. You could make this work by respecting the convention. So for example if you intend to have such an input field in your view:
<input type="file" name="uploadImages" class="input-files" />
then make sure that you have a property on your view model with the same name. And of course of type HttpPostedFileBase.
public HttpPostedFileBase UploadImages { get; set; }
Also in your view make sure you are setting the proper content type of multipart/form-data:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
}
You probably might want to go through the following blog post to better familiarize yourself with the basics of how uploading of files work in ASP.NET MVC. I've also written a similar answer here that you might consult.
So once you add the HttpPostedFileBase property with the UploadImages name in your view model you could adapt your controller action to read the byte array and store it your ImageData property:
[HttpPost]
public ActionResult Create(WilhanWebsite.DomainClasses.Photo photo)
{
if (ModelState.IsValid)
{
photo.DateUploaded = DateTime.Now;
photo.ImageData = new byte[photo.UploadImages.ContentLength];
photo.UploadImages.Read(photo.ImageData, 0, photo.ImageData.Length);
_context.Photos.Add(photo);
_context.SaveChanges();
return RedirectToAction("Index");
}
//we only get here if there was a problem
return View(photo);
}
Now bear in mind that this is an absolutely awful solution. Never do that in a real world application. In a correctly designed application you will have a view model that your controller action will take as a parameter. You're never gonna directly use your autogenerated EF model as parameter to your controller action. You will have a view model with the HttpPostedFileBase property which will be mapped to your domain model.
So in a properly designed application you will have a PhotoViewModel view model class that your controller action will take.
Change this line:
#using (Html.BeginForm())
To this:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
Then change:
<input type="file" name="uploadImages" class="input-files" />
To:
<input type="file" name="ImageData" class="input-files" />
Then change this line:
public byte[] ImageData { get; set; }
To this:
public HttpPostedFileBase ImageData { get; set; }
Finally, use some code like this to read the image into a byte array:
var bs = new byte[ImageData.ContentLength];
using (var fs = ImageData.InputStream)
{
var offset = 0;
do
{
offset += fs.Read(bs, offset, bs.Length - offset);
} while (offset < bs.Length);
}
View:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
...
<input type="file" id="ImageFile" name="ImageFile" .../>
...
}
Controller:
[HttpPost]
public ActionResult Create(Photo photo, HttpPostedFileBase ImageFile)
{
byte[] buf = new byte[ImageFile.ContentLength];
ImageFile.InputStream.Read(buf, 0, buf.Length);
photo.ImageData = buf;
...
}