Upload File From View to Controller in .net Core - asp.net-mvc

I'm trying to create a .net core project with file upload.
In the model I have a class name "Movie" with 2 properties: Image - of type byte[] and Picture - of type IFormFile.
In the view I added a form with the input:
<input asp-for="Picture" type="file" id="image_upload" />
And in my controller I have a function like that:
public IActionResult NewMovie(Movie movie){...
In the movie object that is passed the property Image and Picture are always NULL.
I tried changing the asp-for from Image to Picture, to change the function to be of type Task, to add IFormFile to the function calling and nothing helped.
I never been able to get the file's data. I need it to be of type byte[] but I'll take anything to help me.
Thank you all in advance.

You dont need to store the image in a byte array your model only needs an IFormFile like this:
Model:
[Required(ErrorMessage = "The {0} field is required")]
[Display(Name = "Image")]
[DataType(DataType.Upload)]
public IFormFile Image { get; set; }
Controller:
if (model.Image == null)
return View(model);
string uploadsFolder = Path.Combine(webHostEnvironment.WebRootPath,"Your upload path");
string ImagePath = Guid.NewGuid().ToString() + "_" + model.Image.FileName;
string filePath = Path.Combine(uploadsFolder, ImagePath);
using (FileStream fs = new FileStream(filePath, FileMode.Create))
{
await model.Image.CopyToAsync(fs);
}
Add this to your form tag: enctype="multipart/form-data".
Its essential for the type="file" input to be submitted.
View:
<form enctype="multipart/form-data" Other attributes...>
<div class="custom-file">
<input asp-for="Model.Image" type="file" class="custom-file-input fileUpload" />
<label class="custom-file-label fileLabel">Choose file</label>
</div>
<input type="submit" value="Submit" />
</form>
And finally you save the ImagePath only in your db entity.

Related

MVC how to submit multiple files using one submit button and in Controller retrieve the input file name

I hope my title is understandable. I will try to be as clear as possible. So here's what I am planning to do. I have a Customer Info page which they can upload their documents, in the page, there is two input files which they can upload their documents and then the moment they click submit, I want to fill the Photo and PassportNo variable with the path string so I could retrieve the file later.
What I am struggle with currently is that I manage to upload the files to the system, but I am kinda stuck with updating the filePath into the Photo and PassportNo properties. I can update one of them however I dont know how to retrieve two Input Files. What I meant is that, when the Form Submit, I dont know how to retrieve which type of Input Types are coming from the form (Photo or Passport No).
I want to retrieve the "name" from the Input to the Controller, so in the Controller I can do something like "If its coming from the "name", then do certain update". Hope I am clear enough, if there are other suggestion please feel free to suggest.
Thanks!
Customer Model
public int Id { get; set; }
public string Name { get; set; }
public string Photo { get; set; }
public string PassportNo { get; set; }
View
#using (Html.BeginForm("UploadFiles", "Customer", FormMethod.Post, new {enctype= "multipart/form-data"}))
{
<input type="file" name="Photo" />
<input type="file" name="PassportNo" />
<input type="submit" name="submit" value="Upload Files" />
}
Controller
[HttpPost]
public ActionResult UploadFiles(HttpPostedFileBase Photo)
{
if (Photo.ContentLength > 0)
{
var filename = Path.GetFileName(Photo.FileName);
var path = Path.Combine(Server.MapPath("~/Files/"), filename);
Photo.SaveAs(path);
}
return RedirectToAction("FileForm");
}
just add second parameter to the action
public ActionResult UploadFiles(HttpPostedFileBase Photo, HttpPostedFileBase PassportNo)

MVC Img to Byte[]

My Model
partial class Company
{
... More Properties
public HttpPostedFileBase FilePicture { get; set; }
public byte[] Picture { get; set; }
}
My Controller
[HttpPost]
public ActionResult Edit(int id, Models.Company model)
{
if(model.FilePicture != null)
{
using(Stream inputStream = model.FilePicture.InputStream)
{
MemoryStream memoryStream = inputStream as MemoryStream;
if(memoryStream == null)
{
memoryStream = new MemoryStream();
inputStream.CopyTo(memoryStream);
}
model.Picture = memoryStream.ToArray();
}
}
//EditDefault does the persisting
return this.EditDefault(id, model);
}
My View
#using (Html.BeginForm("Edit", currentController, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
//Clicks on the Picture and the Upload butten are forwarded to the file input tag
//readUrl sets the image as sone as the file changes
<input id="filePicture" type="file" name="filePicture" onchange="readURL(this);">
<button type="button" id="pictureUploadBtnPicture" onclick="$('#filePicture').click();"> Upload</button>
//ClearImg clears the img tag and resets the file input tag
<button type="button" id="pictureDeleteBtnPicture" onclick="clearimg(this);"> Delete</button>
...if Picture not null
...{
<img id="PicturePicture" src="data:image/png;base64,#System.Convert.ToBase64String(#Model.Picture.ToArray())">
<input type="hidden" value="#System.Convert.ToBase64String(#Model.Picture.ToArray())" name="Picture"> **added**
...}
...else ... Render empty Picture and set it per javascript
<input type="submit" value="Safe" class="btn btn-primary">
}
I have a Form which contains some properties like name, city,... and a byte[] which contains the data for a picture. The upload, show and delete are working. My problem now is that when I change something and I safe the site again, the Picture Property is null in the model, that I get in the Post Action. I guess there is something not working with the mapping.
Just to be clear I want the img mapped to the byte[].
Thx in advance for any help :)
Update:
Thx to Matt Tabor ;)
Added a hidden input field and now I get it in the controller.
Updated the View in case somebody needs it.
<img id="Picture" name="Picture" src="data:image/png;base64,#System.Convert.ToBase64String(#Model.Picture.ToArray())">
this property is not an input, when you submit this to the server it wont sumbit the image.
you would have to use something like a hidden input storing the byte array.
try adding this under your image tag
#Html.HiddenFor(m=>m.Picture)

How to get file from HDD to Bitmap object [ASP MVC 3]?

I'm new to ASP MVC and I've been trying to upload a bitmap file from hard drive to a C# Bitmap object, which I would later assign to my Model.
The view (cshtml file) looks like this:
<form action = "DisplayAddedPicture" method=post>
<input type=file name="Picture" id = "Picture"/>
<input type=submit value="Send!" />
</form>
And the DisplayAddedPicture method from controller:
[HttpPost]
public ActionResult DisplayAddedPicture()
{
HttpPostedFileBase File = Request.Files["Picture"];
if (File == null) throw new Exception("NullArgument :( ");
// file stream to byte[]
MemoryStream target = new MemoryStream();
File.InputStream.CopyTo(target);
byte[] TempByteArray = target.ToArray();
// byte[] to Bitmap
ImageConverter imageConverter = new ImageConverter();
Image TempImage = (Image)imageConverter.ConvertFrom(TempByteArray);
Bitmap FinalBitmap = new Bitmap(TempImage);
// (...)
}
It turns out that every time all I get is an Exception, as the HttpPostedFileBase object is always null. Is there any flow in my logic (apart from all of those conversions which come afterwards, I know they're messy) or is there any other way to solve this?
Try this
In your View,
#using (Html.BeginForm("DisplayAddedPicture", "YourControllerName",
FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type=file name="Picture" id = "Picture"/>
<input type=submit value="Send!" />
}
And the Action method
[HttpPost]
public ActionResult DisplayAddedPicture(HttpPostedFileBase Picture)
{
if (Picture!= null && Picture.ContentLength > 0)
{
//Do some thing with the Picture object
//try to save the file here now.
//After saving follow the PRG pattter (do a redirect)
//return RedirectToAction("Uploaded");
}
return View();
}
Try adding the following to your form tag: enctype="multipart/form-data"
<form method="post" action="DisplayAddedPicture" enctype="multipart/form-data">
<input type=file name="Picture" id = "Picture"/>
<input type=submit value="Send!" />
</form>

File upload bound to the Viewmodel

I have a form where I am uploading multiple files and there are a couple of textboxes and some checkboxes associated with each file being uploaded.
I have seen examples for uploading multiple files where the actionresult signature is something like this:
[HttpPost]
public ActionResult Upload(IEnumerable<HttpPostedFileBase> fileUpload)
However, I cant find any example where I can have multiple files uploaded where my actionresult signature is something like this:
[HttpPost]
public ActionResult Upload(MyViewModel vm)
The reason I want this viewmodel being posted is because I think its cleaner than using the FormCollection variable and because I want to each file being uploaded and the data added along with its associated textboxes to be grouped together by way of a List<FileUploadPacket> which will part of the ViewModel
UPDATE
My View model below:
public class EmployeeVM
{
public int EmployeeID {get ;set;}
public string EmpName {get ;set;}
//Other properties
public List<FileUploadPacket> FileUploadPackets { get; set; }
}
The FileUploadPacket class which has the property of type HttpPostedFileBase
public class FileUploadPacket
{
public int FileID {get ;set;}
public string UserEnteredDesc {get ;set;}
//some more other properties
public HttpPostedFileBase UpFile { get; set; }
}
Code snippet of my view.aspx as below
<%: Html.TextBoxFor(model => model.EmpName, new { maxLength = 50 })%>
Upload your files here:
<input type="file" id="UpFile" name="UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[0].UserEnteredDesc )%>
<input type="file" id="UpFile" name="UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[1].UserEnteredDesc )%>
As you can see, I have all the other properties specific to this one file being uploaded kept in its own class. So that in my form an employee can enter his name and upload his files and provide some description and other details for each file. If I move the public HttpPostedFileBase UpFile { get; set; } property to the EmployeeVM class then I will have to collect all the files separately in an array and manually map a file to its description. Is there no way to do this keeping the UpFile property in the FileUploadPacket class itself?
I am using the aspx view engine.
Please help. Thanks for your time...
GetHtml helper is not part of mvc framework, you should look up for third party library containing that helper.
Uploading file that is part of ViewModel is simple though. Basically it goes like this
Define view model
public class MyViewModel
{
public HttpPostedFileBase MyFile { get; set; }
}
Inside Views/Shared/EditorTemplates, create MyViewModel.cshtml
<input type="file" id="MyFile" name="MyFile" />
And view, corresponding to upload action
#model MyViewModel
#using(Html.BeginForm("Upload", "MyController", FormMethod.Post, new { enctype="multipart/form-data"})
{
#Html.EditorForModel()
<input type="submit" value="Upload" />
}
required attribute is important to upload files.
And that's it, once form is submitted, you should see uploaded file inside [HttpPost] action, vm.MyFile.
The fix to this is changing the way you Name and ID the upload control.
<%: Html.TextBoxFor(model => model.EmpName, new { maxLength = 50 })%>
Upload your files here:
<input type="file" id="FileUploadPackets[0].UpFile" name="FileUploadPackets[0].UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[0].UserEnteredDesc )%>
<input type="file" id="FileUploadPackets[1].UpFile" name="FileUploadPackets[1].UpFile" value="ActionHandlerForForm" />
<%: Html.TextBoxFor(model => model.FileUploadPackets[1].UserEnteredDesc )%>
This worked for me!! Hope it helps anyone else out there..

MVC 3 fileupload dialog

I think those tags pretty much says what i'm asking..
I have been struggling with file upload. What I need to achieve is open a dialog for file upload and save it to database, so nothing too fancy.
Basic file upload is more than easy to make. Just form with correct encrypt and input type file. But when I insert my form to dialog something goes wrong and there is nothing in Post. I tried to add test parameters like filename and it worked fine. But the actual file is missing in post.
here's some code:
Form:
#using (Html.BeginForm("Edit", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" })){
<label for="Name">Filename: </label>
<input type="text" name="name" id="name"/>
<input type="file" name="file" id="file" />
<input type="submit"/>
}
Controller:
public ActionResult Edit(Attachment model)
{
var strLen = Convert.ToInt32(model.file.InputStream.Length);
var strArr = new byte[strLen];
model.file.InputStream.Read(strArr, 0, strLen);
return View();
}
Edit:
Model:
public class Attachment
{
public string Name { get; set; }
public HttpPostedFileBase file{ get; set; }
}
This form is inside the dialog.
Try this,
public ActionResult Edit(HttpPostedFileBase file)
{
////
return View();
}

Resources