ASP.net MVC upload image NullReferenceException - c#

I've implemented simple create method to put data in database, and it worked fine. I've decided to add image upload, but I keep getting NullReferenceException (file is null) and I can't figure out why.
I hope you can help me!
Here's my code:
[Authorize]
public ActionResult Create()
{
ViewBag.CategoryId = new SelectList(_categoryRepository.GetAllCategories().AsEnumerable(), "CategoryId",
"Name");
return View();
}
//
// POST: /Advert/Create
[HttpPost, Authorize]
public ActionResult Create(CompetitionDTO competitionDTO, HttpPostedFileBase file)
{
if (file.ContentLength > 0)
{
string fileName = Path.GetFileName(file.FileName);
string fileExtension = Path.GetExtension(fileName);
if ((fileExtension == ".jpg") || (fileExtension == ".png"))
{
string path = Path.Combine(Server.MapPath("~/Uploads/Images"), fileName);
file.SaveAs(path);
competitionDTO.ImageURL = path;
}
}
if (ModelState.IsValid)
{
_competitionRepository.AddCompetition(competitionDTO, WebSecurity.CurrentUserId);
return RedirectToAction("Index");
}
ViewBag.CompetitionId = new SelectList(_competitionRepository.GetAllCompetitions().AsEnumerable(),
"CompetitionId", "Name");
return View(competitionDTO);
}
}
and View
<div>
#using (Html.BeginForm("Create", "Competition", FormMethod.Post, new
{
enctype = "multipart/form-data"
, id = "parentForm"
}))
{
<input type="file" name="file" id="file"/>
<input type="submit" value="Create" />
}
</div>
EDIT
I if I wasn't clear enough:
I know how to insert data to database and I know how to upload file, and I want when I click submit that those 2 things happen at same time

It was my mistake I had two Html.BeginForms, now I merged them into one and it works fine

Related

Return data of file after it has been uploaded

I have referred to some Stack Overflow answers and managed to create an ASP.NET C# application that allows users to upload files (.txt). When I run the application, a page opens in the web browser, which shows “Choose file” and “Ok”. After I choose a file and enter “Ok”, the file is uploaded to an “uploads” folder in the project directory.
How do I edit my code to instead of the file just being uploading to the “uploads” folder, the data in the .txt file is displayed on the web browser page in JSON after I click “Ok” too?
I know that to read file the codes should be something like:
string data = File.ReadAllText(path);
return data;
However i am unsure on how to put these codes in to make the program work as required.
Here is what I have done so far:
Index.cshtml
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data"}))
{
<input type="file" name="file" />
<input type="submit" value="OK" />
}
HomeController.cs
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// extract only the filename
var fileName = Path.GetFileName(file.FileName);
// store the file inside ~/App_Data/uploads folder
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
}
// redirect back to the index action to show the form once again
return RedirectToAction("Index");
}
}
Well, this is a bit awkward but you can do
<div>#ViewBag.JSON</div>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data"}))
{
<input type="file" name="file" />
<input type="submit" value="OK" />
}
Then in your Controller
public ActionResult Index()
{
if(TempData.ContainsKey("JSON") && !string.IsNullOrEmpty((string)TempData["JSON"]))
{
ViewBag.JSON = System.IO.File.ReadAllText((string)TempData["JSON"]);
}
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// extract only the filename
var fileName = Path.GetFileName(file.FileName);
// store the file inside ~/App_Data/uploads folder
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
TempData["JSON"] = path;
file.SaveAs(path);
}
// redirect back to the index action to show the form once again
return RedirectToAction("Index");
}
Update since you don't want to return any html back, change the code like so:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// extract only the filename
var fileName = Path.GetFileName(file.FileName);
// store the file inside ~/App_Data/uploads folder
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
Response.Write(System.IO.File.ReadAllText(path));
return null;
}
// redirect back to the index action to show the form once again
return RedirectToAction("Index");
}

Upload Image ASP.NET MVC

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);

how to update(edit) upload files in asp.net mvc4

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
}

How do I get the value of input file field using MVC5?

I want to let the user select a file from his/her computer, and then upload it to Flickr. The point is that, when I upload a custom image from my computer, it all works fine, but when I add an extra field for the input file but program suddenly doesn't work.
Test.cshtml:
#using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<fieldset>
<input type="file" name="file" />
<input type="submit" value="Upload!" />
</fieldset>
}
HomeController.cs:
public ActionResult Upload(HttpPostedFileBase file, FormCollection form)
{
if (Request.QueryString["oauth_verifier"] != null && Session["RequestToken"] != null)
{
// Flickr relevant code...
var tmpFilePath = Server.MapPath("~/App_Data/Uploads/Pictures");
if (file == null || file.ContentLength == 0)
{
return RedirectToAction("Index"); // It keeps hitting this!
}
var filename = Path.GetFileName(file.FileName);
var path = Path.Combine(tmpFilePath, filename);
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
file.SaveAs(path);
string photoId = flickr.UploadPicture(path, "Test picture");
if (String.IsNullOrEmpty(photoId))
{
System.Diagnostics.Debug.WriteLine("Upload failed!");
}
System.IO.File.Delete(path);
}
else
{
// Flickr relevant code...
}
return View("Test");
}
As long as I know, because MVC is a server-side framework, first of all I need to upload the picture to my server, and then upload it to Flickr. The point is that, I want to put the file in my App_Data/Upload/Pictures folder, and then upload it to Flickr, and afterwards delete it from there. So, I want to keep my server clean.
UPDATE: It keeps hitting the return RedirectToAction("Index"); part, and redirects.
You're missing enctype="multipart/form-data" from you form tag. Without that, file data is not uploaded to the server when the form is submitted.
Change your form call to:
#using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))

How to upload image with custom name with it's original extension?

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);

Categories

Resources