(Preface: this question is about ASP.NET MVC 3.0 which was released in 2011, it is not about ASP.NET Core 3.0 which was released in 2019)
I want to
Most of the answers seems legit enough although I did a sample project for you on donnetfiddle
I'm using LumenWorks.Framework for CSV work but its not a must have.
Demo
View
@using (Html.BeginForm("Index", "Home", "POST"))
{
<div class="form-group">
<label for="file">Upload Files:</label>
<input type="file" multiple name="files" id="files" class="form-control"/><br><br>
<input type="submit" value="Upload Files" class="form-control"/>
</div>
Controller:
[HttpPost]
public ActionResult Index(HttpPostedFileBase upload)
{
if (ModelState.IsValid)
{
if (upload != null && upload.ContentLength > 0)
{
// Validation content length
if (upload.FileName.EndsWith(".csv") || upload.FileName.EndsWith(".CSV"))
{
//extention validation
ViewBag.Result = "Correct File Uploaded";
}
}
}
return View();
}
MemoryStream.GetBuffer() can return extra empty bytes at the end of the byte[], but you can fix that by using MemoryStream.ToArray() instead. However, I found this alternative to work perfectly for all file types:
using (var binaryReader = new BinaryReader(file.InputStream))
{
byte[] array = binaryReader.ReadBytes(file.ContentLength);
}
Here's my full code:
Document Class:
public class Document
{
public int? DocumentID { get; set; }
public string FileName { get; set; }
public byte[] Data { get; set; }
public string ContentType { get; set; }
public int? ContentLength { get; set; }
public Document()
{
DocumentID = 0;
FileName = "New File";
Data = new byte[] { };
ContentType = "";
ContentLength = 0;
}
}
File Download:
[HttpGet]
public ActionResult GetDocument(int? documentID)
{
// Get document from database
var doc = dataLayer.GetDocument(documentID);
// Convert to ContentDisposition
var cd = new System.Net.Mime.ContentDisposition
{
FileName = doc.FileName,
// Prompt the user for downloading; set to true if you want
// the browser to try to show the file 'inline' (display in-browser
// without prompting to download file). Set to false if you
// want to always prompt them to download the file.
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
// View document
return File(doc.Data, doc.ContentType);
}
File Upload:
[HttpPost]
public ActionResult GetDocument(HttpPostedFileBase file)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// Get file info
var fileName = Path.GetFileName(file.FileName);
var contentLength = file.ContentLength;
var contentType = file.ContentType;
// Get file data
byte[] data = new byte[] { };
using (var binaryReader = new BinaryReader(file.InputStream))
{
data = binaryReader.ReadBytes(file.ContentLength);
}
// Save to database
Document doc = new Document()
{
FileName = fileName,
Data = data,
ContentType = contentType,
ContentLength = contentLength,
};
dataLayer.SaveDocument(doc);
// Show success ...
return RedirectToAction("Index");
}
else
{
// Show error ...
return View("Foo");
}
}
View (snippet):
@using (Html.BeginForm("GetDocument", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="submit" value="Upload File" />
}
file upload using formdata
.cshtml file
var files = $("#file").get(0).files;
if (files.length > 0) {
data.append("filekey", files[0]);}
$.ajax({
url: '@Url.Action("ActionName", "ControllerName")', type: "POST", processData: false,
data: data, dataType: 'json',
contentType: false,
success: function (data) {
var response=data.JsonData;
},
error: function (er) { }
});
Server side code
if (System.Web.HttpContext.Current.Request.Files.AllKeys.Any())
{
var pic = System.Web.HttpContext.Current.Request.Files["filekey"];
HttpPostedFileBase filebase = new HttpPostedFileWrapper(pic);
var fileName = Path.GetFileName(filebase.FileName);
string fileExtension = System.IO.Path.GetExtension(fileName);
if (fileExtension == ".xls" || fileExtension == ".xlsx")
{
string FileName = Guid.NewGuid().GetHashCode().ToString("x");
string dirLocation = Server.MapPath("~/Content/PacketExcel/");
if (!Directory.Exists(dirLocation))
{
Directory.CreateDirectory(dirLocation);
}
string fileLocation = Server.MapPath("~/Content/PacketExcel/") + FileName + fileExtension;
filebase.SaveAs(fileLocation);
}
}
Checkout my solution
public string SaveFile(HttpPostedFileBase uploadfile, string saveInDirectory="/", List<string> acceptedExtention =null)
{
acceptedExtention = acceptedExtention ?? new List<String>() {".png", ".Jpeg"};//optional arguments
var extension = Path.GetExtension(uploadfile.FileName).ToLower();
if (!acceptedExtention.Contains(extension))
{
throw new UserFriendlyException("Unsupported File type");
}
var tempPath = GenerateDocumentPath(uploadfile.FileName, saveInDirectory);
FileHelper.DeleteIfExists(tempPath);
uploadfile.SaveAs(tempPath);
var fileName = Path.GetFileName(tempPath);
return fileName;
}
private string GenerateDocumentPath(string fileName, string saveInDirectory)
{
System.IO.Directory.CreateDirectory(Server.MapPath($"~/{saveInDirectory}"));
return Path.Combine(Server.MapPath($"~/{saveInDirectory}"), Path.GetFileNameWithoutExtension(fileName) +"_"+ DateTime.Now.Ticks + Path.GetExtension(fileName));
}
add these functions in your base controller
so you can use them in all controllers
checkout how to use it
SaveFile(view.PassportPicture,acceptedExtention:new List<String>() { ".png", ".Jpeg"},saveInDirectory: "content/img/PassportPicture");
and here is a full example
[HttpPost]
public async Task<JsonResult> CreateUserThenGenerateToken(CreateUserViewModel view)
{// CreateUserViewModel contain two properties of type HttpPostedFileBase
string passportPicture = null, profilePicture = null;
if (view.PassportPicture != null)
{
passportPicture = SaveFile(view.PassportPicture,acceptedExtention:new List<String>() { ".png", ".Jpeg"},saveInDirectory: "content/img/PassportPicture");
}
if (view.ProfilePicture != null)
{
profilePicture = SaveFile(yourHttpPostedFileBase, acceptedExtention: new List<String>() { ".png", ".Jpeg" }, saveInDirectory: "content/img/ProfilePicture");
}
var input = view.MapTo<CreateUserInput>();
input.PassportPicture = passportPicture;
input.ProfilePicture = profilePicture;
var getUserOutput = await _userAppService.CreateUserThenGenerateToken(input);
return new AbpJsonResult(getUserOutput);
//return Json(new AjaxResponse() { Result = getUserOutput, Success = true });
}
You don't use a file input control. Server side controls are not used in ASP.NET MVC. Checkout the following blog post which illustrates how to achieve this in ASP.NET MVC.
So you would start by creating an HTML form which would contain a file input:
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" />
<input type="submit" value="OK" />
}
and then you would have a controller to handle the upload:
public class HomeController : Controller
{
// This action renders the form
public ActionResult Index()
{
return View();
}
// This action handles the form POST and the upload
[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");
}
}
In the view:
<form action="Categories/Upload" enctype="multipart/form-data" method="post">
<input type="file" name="Image">
<input type="submit" value="Save">
</form>
while the following code in the controller:
public ActionResult Upload()
{
foreach (string file in Request.Files)
{
var hpf = this.Request.Files[file];
if (hpf.ContentLength == 0)
{
continue;
}
string savedFileName = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, "PutYourUploadDirectoryHere");
savedFileName = Path.Combine(savedFileName, Path.GetFileName(hpf.FileName));
hpf.SaveAs(savedFileName);
}
...
}