I have a view model that has a HttpPostedFileBase property called 'StudentImage'. When the user logs in I want to fetch a byte array (my image from DB) and display it? I can fetch the byte[] from the database, and I can set the byte[] back to my HttpPostedFileBase Image by setting a memory stream that inherits from httppostedfilebase. But no image shows up on my form
Here is my view model
public class EditStudentViewModel
{
...other code here
public HttpPostedFileBase StudentImage { get; set; }
}
Here is my controller where I fetch the byte array and I want to set the byte[] to 'StudentImage', which is a HttpPostedFileBase
public ActionResult Edit()
{
var years = Enumerable.Range(DateTime.Now.Year - 100, 100).Reverse();
string userId = User.Identity.GetUserId();
Student student = studentRepository.Find(userId);
// student.StudentImage => this is a byte array that I need to get
// into the HttpPostedFileBase named StudentImage into
// 'EditStudentViewModel'
var studentViewModel = new EditStudentViewModel
{
...other properties set here
StudentImage = new MemoryFile(new MemoryStream(student.StudentImage.Image));
};
I created a new class called MemoryFile and inherited HttpPostedBaseFIle like so
class MemoryFile : HttpPostedFileBase
{
Stream stream;
public MemoryFile(Stream stream)
{
this.stream = stream;
}
public override Stream InputStream
{
get { return stream; }
}
}
it seems to set the values correctly, but when I view the form on the screen I don't see the image! It doesn't set it with the Bootstrap File Plugin I'm using that can be found here BootStrap File Upload Plugin
Here is my javascript for the file uplaod plugin
$("#input-20").fileinput({
'type': 'POST',
'cache': false,
'browseClass': 'btn btn-primary btn-block',
'showCaption': false,
'showRemove': false,
'showUpload': false,
'uploadAsync': false,
'maxFileCount': 1,
'allowedFileExtensions': ['jpg', 'png', 'gif'],
'allowedFileTypes': ['image'],
//'uploadUrl': '#Url.Action("Edit", "Student")'
});
Here is my HTML tag
<div class="panel-body">
#Html.TextBoxFor(model => model.StudentImage, new { #type = "file", #id = "input-20" })
</div>
You cannot show an image in an <input type="file" />, you must use a <img> tag. When you do #Html.TextBoxFor(x => x, new { type="file" }), the rendered output will be an <input type="file" />, nothing special.
If you need to show the existing image, you should do it something like this:
<div class="panel-body">
<!-- show the current StudentImage in the database -->
<img src="#Url.Action("GetStudentImage", new { studentID= Model.StudentImageID })" />
<!-- for adding a new StudentImage -->
#Html.TextBoxFor(model => model.StudentImage, new { #type = "file", #id = "input-20" })
</div>
Your action in the controller would look like this, based on the links I posted in the comments:
public ActionResult GetStudentImage(int studentImageID)
{
Student student = studentRepository.Find(studentID);
return File(student.StudentImage.Image, "image/jpg");
}
Related
Hey I want to upload picture and save that picture to a folder, and save the name of that picture to DB in addition I am also using model binding for other fields of form. Here is the code in this HttpPostedFileBase file receives null I am also using enctype = "multipart/form-data" in my form.
public ActionResult UmrahPackage(PackagesModel model, , HttpPostedFileBase file)
{
try
{
if (model.ID == 0)
{
String fileName = "";
Pakage pkg = new Pakage();
pkg.Title = model.Title;
pkg.PackageDetail = model.PackageDetail;
pkg.Duration = model.Duration;
if (file != null)
{
fileName = System.Guid.NewGuid().ToString() + System.IO.Path.GetExtension(file.FileName);
string physicalPath = Server.MapPath("~/Images/Uploads" + fileName);
// save image in folder
file.SaveAs(physicalPath);
}}
In addition I am also trying this but I am not be able to understand that how to save image in folder I mean the object instance before SaveAs -> file
if (Request.Files.Count > 0 && String.IsNullOrEmpty(Request.Files[0].FileName) == false)
{
HttpPostedFileBase file;
fileName = System.Guid.NewGuid().ToString() + System.IO.Path.GetExtension(Request.Files[0].FileName);
string physicalPath = Server.MapPath("/uploads/profileimages/") + fileName;
file.SaveAs(physicalPath);
}
My form looks like,
#using (Html.BeginForm("UmrahPackage", "Home", FormMethod.Post, new { enctype = "multipart/form-data"}))
{
#Html.HiddenFor(model => model.ID)
<label>Title:</label>
#Html.TextBoxFor(model => model.Title)
<label>Upload Image</label>
<input type="file" id="imgInp">
<button type="submit" >Create</button>
}
Kindly help me, Thanks.
Your input element name attribute value should match with your parameter name
Since your HttpPostedFileBase parameter name is file, give the same name for your file input.
<input type="file" name="file" />
Now when the form is submitted, model binder will be able to map your submitted form data to your parameter named file
I also suggest you to use Path.Combine instead of string concatenation.
string physicalPath = Path.Combine(Server.MapPath("~/Images/Uploads"), fileName);
I had referred to this link to fix the problem of overwriting previously selected files. But this method has led to another problem. The pictures selected were duplicated. Meaning that if I choose 3 pictures, it would save 6.
The following code is my javascript
<input type="file" id="files" name="files" class="btn" style="color:white" multiple />
function previewImages() {
linebreak = document.createElement("br");
var preview = document.querySelector('#preview');
if (this.files) {
[].forEach.call(this.files, readAndPreview);
}
function readAndPreview(file) {
// Make sure `file.name` matches our extensions criteria
if (!/\.(jpe?g|png|gif)$/i.test(file.name)) {
$('#files').val('');
return alert(file.name + " is not an image");
} else if (file.size > 4194304) {
$('#files').val('');
return alert(file.name + "is larger than 4MB");
} else {
var reader = new FileReader();
reader.addEventListener("load", function () {
var image = new Image();
image.height = 100;
image.title = file.name;
image.src = this.result;
preview.append(image.title);
preview.appendChild(image);
});
reader.readAsDataURL(file);
}
}
}
//document.querySelector('#files').addEventListener("change", previewImages);
$(document).on('change', 'input[type="file"][multiple]', function () {
var $this = $(this);
$this.clone().insertAfter($this);
$this.hide();
});
$(document).on('change', 'input[type="file"][multiple]', previewImages);
I want make form edit for my upload files, so I want the file delete after the new file uploaded
this for my RazorView
#model updownload.Models.updown
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.HiddenFor(x => x.id)
<div class="container">
<div>
#Html.ValidationMessage("uploadError")
#Html.TextBoxFor(x => x.upload, new { type = "file", id = "file" })
</div>
<div class="form-group">
<label>Username:</label>
#Html.TextBoxFor(x => x.keterangan)
</div>
<div class="button">
<button>Submit</button>
</div>
</div>
}
and this for my Edit controller
[HttpPost]
public ActionResult Edit(updown viewModel, HttpPostedFileBase file)
{
var currentupdown = db.updowns.Find(viewModel.id);
if (viewModel.upload != null)
{
System.IO.File.Delete(Path.Combine(Server.MapPath("~/App_Data/upload"), viewModel.upload));
string fileName = Guid.NewGuid() + Path.GetFileName(file.FileName);
string path = Path.Combine(Server.MapPath("~/App_Data/upload"), fileName);
file.SaveAs(path);
viewModel.upload = fileName;
}
else
{
currentupdown.upload = currentupdown.upload;
}
currentupdown.keterangan = viewModel.keterangan;
db.SaveChanges();
return RedirectToAction("List", "Home");
}
I got error in this line string fileName = Guid.NewGuid() + Path.GetFileName(file.FileName);
can someone fix my code please.
sorry for my bad english
You are getting a typical null reference exception because file is NULL and you are trying to access the FileName property on that.
Why is file null ?
For file upload to work from a form, the form should have enctype attribute with value set to "multipart/form-data". Your current view code will generate the form tag without that.
<form action="/Home/Edit" method="post">
</form>
So first fix that.Also, for the file uploading to work, your file input element's name attribute value must match with the name of your HttpPostedFileBase parameter.
#using (Html.BeginForm("Edit", "Home", FormMethod.Post,
new { enctype = "multipart/form-data"}))
{
#Html.LabelFor(a => a.keterangan)
#Html.TextBoxFor(a => a.keterangan)
#Html.HiddenFor(x => x.id)
<input type="file" name="file"/>
<input value="submit" type="submit" class="btn" />
}
This will render the correct HTML markup needed to send the file.
Now in the server action method, you need to d a null check on the file parameter before trying to access that.
[HttpPost]
public ActionResult Edit(updown viewModel, HttpPostedFileBase file)
{
var currentupdown = db.updowns.Find(viewModel.id);
if (file != null)
{
var location=Server.MapPath("~/App_Data/upload");
//Delete existing file
if (!string.IsNullOrEmpty(currentupdown.upload))
{
var existingFile= Path.Combine(location, currentupdown.upload);
if (System.IO.File.Exists(existingFile))
{
System.IO.File.Delete(existingFile);
}
}
var fileName = Guid.NewGuid() + Path.GetFileName(file.FileName);
var path = Path.Combine(location, fileName);
file.SaveAs(path);
currentupdown.upload = fileName; // Update to the new file name
}
currentupdown.keterangan = viewModel.keterangan;
db.SaveChanges();
return RedirectToAction("List", "Home");
}
Since you have a view model, you can also add a new property to the viewmodel called File (of type HttpPostedFileBase) and simply use that in your server action. With this you can remove the second parameter as your view model already has a property for this. So instead of checking if(file!=null), you would be doing if(viewmodel.File!=null)
public class YourViewModel
{
public int Id { set;get;}
public string Keterangan { set;get;}
public HttpPostedFileBase File { set;get;}
}
and
[HttpPost]
public ActionResult Edit(YourViewModel viewModel)
{
// use viewModel.File as needed
}
I want to upload Pdf file into my application
So I have ViewModel (I post only relevant code)
public class SubcategoryViewModel
{
public HttpPostedFileBase PdfFile { get; set; }
[DisplayName("PDF")]
public string Pdf { get; set; }
}
Controller:
public async Task<string> CreateSubcategory(SubcategoryViewModel model)
{
string pdf = null;
if (model.Pdf != null)
{
pdf = Guid.NewGuid().ToString().Substring(0, 13) + "_" + model.File.FileName;
model.Pdf = pdf;
var path = Path.Combine(HttpContext.Current.Server.MapPath("~/Content/pdf"), pdf);
model.File.SaveAs(path);
}
var subcategory = new Subcategory
{
Pdf = pdf,
};
db.SubcategoriesList.Add(subcategory);
await db.SaveChangesAsync();
View:
#model Models.ViewModels.SubcategoryViewModel
#using (Html.BeginForm("Create", "Subcategory", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
#Html.LabelFor(model => model.Pdf, new { #class = "control-label col-md-2" })
<div class="col-md-10 legend-size">
<input type="file" id="file" name="file" />
</div>
</div>
When I action post I don´t received nothing into model.Pdf, so into if (model.Pdf != null) validation it comes null, and I don´t know why
Anyone have idea why it occurs? Thankyou in advance!
You have 2 main issues. First the name of your file input is name="file", but that does not match the property in your model. It needs to be
<input type="file" name="PdfFile" />
Second, you never generate an input for property string Pdf so in the POST method, it will always be null and therefore the code inside your if (model.Pdf != null) will never be executed. However, what you really want is to save the file if its not null, so the code needs to be
public async Task<string> CreateSubcategory(SubcategoryViewModel model)
{
string fileName = null;
if (model.PdfFile != null && model.PdfFile .ContentLength > 0)
{
fileName = Guid.NewGuid().ToString().Substring(0, 13) + "_" + model.PdfFile.FileName;
string path = Path.Combine(HttpContext.Current.Server.MapPath("~/Content/pdf"), fileName);
model.PdfFile.SaveAs(path);
}
var subcategory = new Subcategory
{
Pdf = fileName ,
};
db.SubcategoriesList.Add(subcategory);
await db.SaveChangesAsync();
Side note: I would also recommend an additional property in your model for the files display name (i.e. the value of model.PdfFile.FileName) so that you can use that in your view rather than displaying the name prefixed with a Guid which would have little meaning to the user. Refer this answer for an example.
I think your problem is you are getting null value in PdfFile property of your model. This is because you have not given name attribute of file upload control same as you property. change name attribute of your file upload control to PdfFile.
<input type="file" id="file" name="PdfFile" />
So I have file uploading input which is strongly typed and below is the model class
public class UploadImageAlbum
{
[CustomFileValidator]
public HttpPostedFileBase Images { get; set; }
}
and my CustomFileValidator class is as below:
[AttributeUsage(AttributeTargets.Property,AllowMultiple =true,Inherited =false)]
public class CustomFileValidator : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
const int maxContent = 1024 * 1024 * 50;//50 MB
var sAllowedExt = new string[] { ".jpg", ".png" };
var file = value as HttpPostedFileBase;
//Check for null
if (file == null)
{
return new ValidationResult("Please select an image to upload");
}
//Check for File Extension
if (sAllowedExt.ToList().Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
{
return new ValidationResult("Please Upload a valid file of type : " + string.Join(",", sAllowedExt));
}
//Check for length of file
if(file.ContentLength>maxContent)
{
return new ValidationResult("File is too large, maximum allowed size is :" + (maxContent / 1024) + "MB");
}
return ValidationResult.Success;
}
}
and my partialview is as below:
#using (Html.BeginForm("UploadImages", "Admin", FormMethod.Post, htmlAttributes: new { id = "frmUploadImages", novalidate = "novalidate", autocomplete = "off", enctype = "multipart/form-data" }))
{
<div class="form-group">
<span class="btn btn-default btn-file-img">
Browse #Html.TextBoxFor(m => m.UIAModel.Images, new { type = "file", multiple = "multiple", data_charset = "file" })
</span>
<span class="text-muted" id="filePlaceHolder">No files selected</span>
#Html.ValidationMessageFor(m=>m.UIAModel.Images, null, htmlAttributes: new { #class = "invalid" })
</div>
<div class="form-group">
<button class="btn btn-primary addImage pull-right">
<i class="fa fa-upload"></i> Upload
</button>
</div>
}
and below is how I load partialview on click of a link:
$('#page-inner').empty().load('/Admin/GetMediaUploadView', function () {
$.validator.unobtrusive.parse($('form#frmUploadImages'));
//Apply client validation for partialviews
})
But even after following all the steps, it isn't displaying any message and point to note is, if I add [Required] attribute for the same, it will work well, but custom validation what I have never displays any message. What else I have to add to make this CustomValidator to work? I followed this post but still could not be of much help. Also if anyone let me know how to update this model so as to accept multiple images, it will be of great help.
In order to get client side validation, your attribute must
implement IClientValidatable which will add the associated
data-val-* attributes to you html, and
you must include scripts to add methods to the jQuery validator.
This article is a good guide to creating custom client and server side validation attributes.
Note also your current attribute is rather limited in that the file types and size are fixed, and it would be more flexible to include properties to specify the file types and maximum file size so that you could use it as (say)
[FileValidation(MaxSize="1024", FileType="jpg|png")]
public HttpPostedFileBase Images { get; set; }
This article provide an example of an attribute that validates the file type, but could be adapted to include the MaxSize property.
Side note: If your loading dynamic content, then you should first set the validator to null
var form = $('form#frmUploadImages');
form.data('validator', null);
$.validator.unobtrusive.parse(form);
I'm growing thin learving mvc3. I have the following code in my controller
[HttpPost]
public ActionResult Accreditation(Accreditation accreditation)
{
if (ModelState.IsValid)
{
var fileUpload = Request.Files[0];
var uploadPath = Server.MapPath("~/App_Data/uploads");
using (var fs = new FileStream(Path.Combine(uploadPath, accreditation.PressCard.ToString()), FileMode.Create))
{
var buffer = new byte[fileUpload.InputStream.Length];
fileUpload.InputStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
}
context.Accreditations.Add(accreditation);
context.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.PossibleNationalities = context.Nationalities;
ViewBag.PossibleNchis = context.Nchis;
ViewBag.PossibleMedia = context.Media;
ViewBag.PossibleEmploymentStatus = context.EmploymentStatus;
return View(accreditation);
}
}
Here's the View:
#using (Html.BeginForm("Accreditation", "Home", new { enctype = "multipart/form-data" }, FormMethod.Post))
{
#Html.ValidationSummary(true)
.............
.............
<div class="editor-field">
<input type="file" name="PressCard" id="PressCard" data-val-required="Press card is required" data-val="true"/>
#Html.ValidationMessageFor(model => model.PressCard)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Passport)
</div>
<div class="editor-field">
<input type="file" name="Passport" id="Passport" data-val-required="ID/Passport is required" data-val="true"/>
#Html.ValidationMessageFor(model => model.Passport)
</div>
.......
........
When I try to upload, i get the following error message:
Exception Details: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
Any one out there with a pointer to the right direction?
sorry for delay. Here's the new code
[HttpPost]
public ActionResult Accreditation(Accreditation accreditation, HttpPostedFileBase Passport)
{
if (ModelState.IsValid)
{
var uploadPath = Server.MapPath("~/App_Data/uploads");
using (var fs = new FileStream(Path.Combine(uploadPath, accreditation.PressCard.ToString()), FileMode.Create))
{
var buffer = new byte[Passport.InputStream.Length];
Passport.InputStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, buffer.Length);
}
context.Accreditations.Add(accreditation);
context.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.PossibleNationalities = context.Nationalities;
ViewBag.PossibleNchis = context.Nchis;
ViewBag.PossibleMedia = context.Media;
ViewBag.PossibleEmploymentStatus = context.EmploymentStatus;
return View(accreditation);
}
}
Are really uploading data? I'd suggest you use this way. Create a parameter of type HttpPostedFileBase with the same name as the input field and test for its content length property.
Don't forget to use the same name for the parameter and for the input tag.
Checking this link will the fastest way for you to move on.
MVC 3 file upload and model binding
var fileUpload = Request.Files[0]; is the line where you have your exception, isn't it? You should expect the file to be stored in the property of class Accreditation, not in Request.Files.
So you need properties PressCard and Passport in Accreditation, both of type HttpPostedFileBase, and then use these properties in your code.
Get your posted file directly in action:
Here is discussion on SO: MVC 3 file upload and model binding
[HttpPost]
public ActionResult Accreditation(Accreditation accreditation, HttpPostedFileBase Passport)
{
...
}