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" />
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
}
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 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");
}
I'm trying to upload images in a form which I basically have done already, but I want the image to be named specifically for each user who registers.
For example, each email will be unique, if there is another email already in the database then the form will return false (it will not let him/her register).
So what I did was change the file name to the email he/she typed in the form.
But now the file will not have it's original extension (.jpg .png etc).
Is there a way I could pull the file original extension?
Here's what I have in my controller:
[HttpPost]
public AcitonResult Register(Registration signingUp, HttpPostedFileBase avatar)
{
var db = new AvatarDBEntities();
if (ModelState.IsValid)
{
var FindEmail = db.tblProfiles.FirstOrDefault(e => e.PROF_Email == signingUp.Email);
if (FindEmail == null)
{
var Data = db.tblProfiles.Create();
Data.PROF_Email = signingUp.Email;
if (avatar != null)
{
string profpic = System.IO.Path.GetFileName(avatar.FileName);
string profpic_name = signingUp.Email + ".jpg"; //this is what I'm trying to change
string path = System.IO.Path.Combine(Server.MapPath("~/assets/images/user_images/avatars"), profpic_name);
avatar.SaveAs(path);
}
db.tblProfiles.Add(Data);
db.SaveChanges();
}
else
{
ModelState.AddModelError("Email", "That Email already exist.");
return View();
}
}
return View();
}
View:
#using (Html.BeginForm("Register", "Main", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.TextBoxFor(r => r.Email, new { #class = "custom-input Email" })<br/>
#Html.ValidationMessageFor(a => a.Email)<br/>
<label for="avatar">Profile picture:<span class="required">*</span></label><br />
<input type="file" name="avatar" id="avatar" /><br/>
<input type="submit" />
}
The image is in the folder with the name as their email and the extension of .jpg.
I just want to pull the extension of the original file and add it after it pulls the email value.
Thanks.
What I think you're looking for is
Path.GetExtension(string fileName)
So your code becomes
string profpic_name = signingUp.Email + Path.GetExtension(avatar.FileName);
There is a method called Path.GetExtension
Store the extension in a temp variable first, then use it later.
string tempExtension = Path.GetExtension(avatar.FileName);