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>
Related
OK, so I am trying to make the move to MVC.
I have a Model, view and Controller made, but now I want to change the create functionality of the app.
I am working with uploads and I have this system generated code in my contoller.
Function Create(<Bind(Include:="Id,Course,Category,SubCategory,FileName,FileType,UploadedBy,DateUploaded")> ByVal acAsset As acAsset) As ActionResult
If ModelState.IsValid Then
db.Assets.Add(acAsset)
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(acAsset)
End Function
Now I want to change this so that it will
Check for the existence of a folder for Course, Category and Sub category. If this folder is not there it must be created.
Upload the file select by a file selection box.
Post the files' name to the db.
The code is not necessarily the issue, I am jut not sure where I should put in the controller?
I have read this article but is not dealing with the DB post.
Thank you in advance.
You just add your code in controller that you want to hit on button click
Your Razor View Code
#using (Html.BeginForm("Upload", "Upload", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="submit" name="Submit" id="Submit" value="Upload" />
}
C# Code
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/"), fileName);
file.SaveAs(path);
}
return RedirectToAction("UploadDocument");
}
}
In your View
<input type="file" name="file">
In your Controller
public actionresult(HttpPostedFileBase file)
{
string filename = Path.GetFileName(file.FileName);
string contentType = file.ContentType;
using (Stream fs = file.InputStream)
{
using (BinaryReader br = new BinaryReader(fs))
{
byte[] bytes = br.ReadBytes((Int32)fs.Length);
}
}
//Data Context Code here
tableName.File= bytes;
db.add(tableName);
db.SaveChanges();
}
I'm trying to do my first simple file upload in MVC 5. I'm following a bunch of examples I've found but for some reason in my "Create" ActionResult the uploadFile is always coming in as NULL so the upload code is never running. Anyone see what I might be doing wrong?
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Documents.</h2>
<h4>Upload a new document.</h4>
<div class="well">
#using (Html.BeginForm("Create", "Documents", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<h3>Select a file to upload. </h3>
<input type="file" name="files" value="" multiple="multiple" />
<input type="submit" value="Upload your file" title="Upload" />
<div style="color:Red;font-size:14px">#ViewBag.Message</div>
}
</div>
Here is my controller:
// POST: Documents/Create
[HttpPost]
public ActionResult Create(HttpPostedFileBase uploadFile)
{
try
{
if(uploadFile != null && uploadFile.ContentLength > 0)
{
string filePath = Server.MapPath("../SiteDocuments" + uploadFile.FileName);
uploadFile.SaveAs(filePath);
}
return RedirectToAction("Index");
}
catch (Exception ex)
{
return View();
}
}
Your file input element's name should match to your action method parameter name.
So update your HTML markup to have the same name attribute value.
<input type="file" name="uploadFile" value="" multiple="multiple" />
and your action method will be
[HttpPost]
public ActionResult Create(HttpPostedFileBase uploadFile)
{
// do something
}
Or change your action method parameter name to match with your file input element name.
<input type="file" name="files" value="" multiple="multiple" />
and your action method will be
[HttpPost]
public ActionResult Create(HttpPostedFileBase files)
{
if(files!= null && files.ContentLength > 0)
{
// do something
}
}
When you add multiple="multiple" attribute to the input element, the browser will allow the end user to select more than one file at a time. In that case If your action method parameter is a single instance of HttpPostedFileBase object, It will receive the first file from the selected n files. If you want all the files, You may change your parameter to a collection such as
[HttpPost]
public ActionResult Create(IEnumerable<HttpPostedFileBase> files)
{
if (files != null && files.Any())
{
foreach (var file in files)
{
if (file.ContentLength > 0)
{
//do something
}
}
}
}
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)
View:
#using (Html.BeginForm("Edit","program","",FormMethod.Post,new {enctype = "multipart/form-data"}))
{
<div class="upload">
<input type="file" name="files" id="EpExpert"/>
<input type="file" name="files" id="EpNewbie"/>
<input type="submit" name="submit" value="submit" id="submit"/>
</div>
}
Controller:
[HttpPost]
public ActionResult Edit(tr_program program, IEnumerable<HttpPostedFileBase> files)
{
foreach (var file in files)
{
if (file != null)
{
//string extension = Path.GetExtension(file.FileName);
string path = AppDomain.CurrentDomain.BaseDirectory + "Documents/Program-PDFs/";
string filename = Path.GetFileName(file.FileName);
file.SaveAs(Path.Combine(path, filename));
}
}
}
uploaded file name should be in file-{id}.pdf
eg: file-EpNewbie.pdf
file-EpExpert.pdf
PLEASE help!!
The id is never sent to the server. You could use the name attribute instead:
#using (Html.BeginForm("Edit", "program", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="upload">
<input type="file" name="EpExpert" />
<input type="file" name="EpNewbie" />
<input type="submit" name="submit" value="submit" id="submit"/>
</div>
}
and in your controller action:
[HttpPost]
public ActionResult Edit(tr_program program)
{
string location = Server.MapPath("~/Documents/Program-PDFs");
foreach (string name in Request.Files)
{
HttpPostedFileBase file = Request.Files[name];
string filename = string.Format("file-{0}.pdf", name);
filename = Path.Combine(location, filename);
file.SaveAs(filename);
}
...
}
Obviously since you are storing all the files in the same location (~/Documents/Program-PDFs) with the same names (file-EpExpert.pdf and file-EpNewbie.pdf) if 2 users upload different files at the same time they might get overwritten. There seems to be a problem with your design and naming convention but in my answer I illustrated how you could pass the name of the file input to the controller action which could be used to build the resulting filename. Now it's up to you to take this into consideration when building your real application.
You can take an idea from here. Firstly declare id and data-id dynamic. for example
id = '#model.Id' data-id = '#model.Id'
Before submit form, use js or jquery take id value, then post form.
$("#myForm").submit(function () {
var idValue = $(this).attr('data-id');
document.getElementById('yourHiddenValue').value = idValue;
});
I have a problem when I upload a file in ASP.NET MVC.
My code is below:
View:
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index2</h2>
#using (Html.BeginForm("FileUpload", "Board", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" />
<input type="submit" />
}
Controller:
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase uploadFile)
{
if (uploadFile != null && uploadFile.ContentLength > 0)
{
string filePath = Path.Combine(Server.MapPath("/Temp"), Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(filePath);
}
return View();
}
But uploadFile always returns null.
Can anyone figure out why??
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index2</h2>
#using (Html.BeginForm("FileUpload", "Board", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="uploadFile"/>
<input type="submit" />
}
you have to provide name to input type file to uploadFile in order to model binding work in ASP.net mvc and also make sure that name of your input type file and argument name of HttpPostedFileBase is identical.
I had tried most of the solutions posted online for this topic, but found it better to use a workaround instead..
It really didn't matter what I did the HttpPostedFileBase and/or HttpPostedFile were always null. Using the HttpContext.Request.Files collection seemed to work with no hassles at all.
e.g.
if (HttpContext.Request.Files.AllKeys.Any())
{
// Get the uploaded image from the Files collection
var httpPostedFile = HttpContext.Request.Files[0];
if (httpPostedFile != null)
{
// Validate the uploaded image(optional)
// Get the complete file path
var fileSavePath =(HttpContext.Server.MapPath("~/UploadedFiles") + httpPostedFile.FileName.Substring(httpPostedFile.FileName.LastIndexOf(#"\")));
// Save the uploaded file to "UploadedFiles" folder
httpPostedFile.SaveAs(fileSavePath);
}
}
In the above example I only grab the first file, but it is just a matter of looping though the collection to save all files.
HTH
Rob
In my scenario the problem was with id attribute, I had this:
<input type="file" name="file1" id="file1" />
The soultion was to remove id:
<input type="file" name="file1" />
While not the answer to this specific user, I would like to point out that HTML requires that the form tag has an enctype attribute with the value multipart/form-data. And of course both the attribute and it's value must be correct.
For mvc, this means that when using beginform, you should use the version with the htmlAttributes parameter
There can be another scenario also. In my case, I was getting this issue because I was directly rendering script tag in my MVC view and IE is giving issue there.
Correct code in view should be as below:
#section scripts
{
<script>
$(document).ready(function () {
$('.fileinput').fileinput();
...
}
You need to use Razor code to set Name of the input file.
<input type="file" name="#Html.Namefor(m => m.propertyName)">