MVC upload and save form image with Ajax - javascript

I have a form with 3 inputs (text, image, submit button).
#using (Html.BeginForm("Save", "User", FormMethod.Post, new {Id="Form1", enctype = "multipart/form-data"}))
{
<input id="FileUploadInput" name="Image" type="file"/>
<input id="FirstName" Name="FirstName">
<input type="submit" id="inputSubmit" value="Save" />
}
Now i want to submit this form from javascript with AJAX
$("#inputSubmit").click(function (e) {
e.preventDefault();
var form = $("#Form1");
form.validate();
if (form.valid()) {
$.ajax({
url: "/User/Save",
data: form.serialize(),
type: "POST",
success: function (data) {
if (data === "") {
location.reload();
}
else {
$(".content").html(data);
$.validator.unobtrusive.parse($(".content"));
}
}
});
}
return false;
});
In my controller file i have.
public ActionResult Save(UserProfileSettings settings)
{
var image = setings.Image
var name = settings.Firstname
}
My model
public class UserProfileSettings
{
public string FirstName { get; set; }
public HttpPostedFileBase Image { get; set; }
}
The problem is that in my controller method i am getting settins.FirstName, but settings.Image is always null. I think, that with this method it is not possible to serialize image file.

try use jquery plugin muliple upload:
http://blueimp.github.io/jQuery-File-Upload/

As Darin Dimitrov suggested before, it's better to use jquery forms plugin. I have already posted this in my another answer here.
Quick Example
View
#using (Ajax.BeginForm("YourAction", "YourController", new AjaxOptions() { HttpMethod = "POST" }, new { enctype = "multipart/form-data"}))
{
#Html.AntiForgeryToken()
<input type="file" name="files"><br>
<input type="submit" value="Upload File to Server">
}
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public void YourAction(IEnumerable<HttpPostedFileBase> files)
{
if (files != null)
{
foreach (var file in files)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// extract only the fielname
var fileName = Path.GetFileName(file.FileName);
// TODO: need to define destination
var path = Path.Combine(Server.MapPath("~/Upload"), fileName);
file.SaveAs(path);
}
}
}
}

Related

add more picture instead of replacing picture in asp.net core mvc

i create a form where i upload picture into database in asp.net core mvc using ado.net.i face an issue that when i select picture it selects the picture but if i do one more time instead of add more picture it replace that picture which i select first help me to that thing in which i add further more picture. i create a list in which i upload the picture.Here is my code.
My Controller:
public IActionResult aprent([Bind] RentModel ar )
{
try
{
if (ModelState.IsValid)
{
if(ar.imge1 != null && ar.imge1.Count>0)
{
string folder = "image/";
foreach (IFormFile imge in ar.imge1)
{
folder += Guid.NewGuid().ToString() + "_" + imge.FileName;
ar.pic1 = "/" + folder;
string serverFolder = Path.Combine(_IWebHostEnvironment.WebRootPath, folder);
imge.CopyTo(new FileStream(serverFolder, FileMode.Create));
}
}
string res = DB.Saverecord(ar);
string pics = DB.imagedb(ar);
TempData["msg"] = res;
}
}
catch (Exception ex)
{
TempData["msg"] = ex.Message;
}
return View();
}
My Model:
public string? pic1 { get; set; }
public IFormFileCollection imge1 { get; set; }
My View:
<div class="row">
<input type="file" name="imge1" id="file" asp-for="imge1" class="hidden" multiple>
<button type="button" class="btn btn-primary" id="filebutton"><span id="filetext">Select File</span></button>
<div id="preview"></div>
</div>
<div id="image_preview"></div>
<script>
$(document).ready(function () {
$('#filebutton').click(function () {
$('#file').click();
});
$('#file').change(function () {
var name = $(this).val().split('\\').pop();
var file = $(this)[0].files;
if (name != '') {
if (file.length >= 2) {
$('#filetext').html(file.length + ' files ready to upload');
}
else {
$('#filetext').html(name);
}
}
});
$('#file').on("change", previewImages);
});
function previewImages() {
var $preview = $('#preview').empty();
if (this.files) $.each(this.files, readAndPreview);
function readAndPreview(i, file) {
if (!/\.(jpe?g|png|gif)$/i.test(file.name)) {
return alert(file.name + " is not an image");
} // else...
var reader = new FileReader();
$(reader).on("load", function () {
$preview.append($("<img>", { src: this.result, height: 80, }));
});
reader.readAsDataURL(file);
}
}
</script>
Do you want to choose more pictures at one time ?
Something like below? Hold down the Shift key when you choose pictures.
Update
if i select picture and after that i hit the choose button one more
time it select further more picture but not replace the previous
selected picture
i have also other data also i have same model in which my data exist
when i post form
You can try to use jQuery FilePond.
Below is a work demo, you can refer to it.
TestController:
public class TestController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(Testmodel testmodel,IFormFile[] photos)
{
return View();
}
}
Testmodel:
public class Testmodel
{
public string Name { get; set; }
public IList<IFormFile> photos { get; set; }
}
Index view:
#model Testmodel
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="https://unpkg.com/filepond/dist/filepond.min.js"></script>
<script src="https://unpkg.com/jquery-filepond/filepond.jquery.js"></script>
<link href="https://unpkg.com/filepond/dist/filepond.css" rel="stylesheet"/>
<script src="https://unpkg.com/filepond/dist/filepond.js"></script>
<form id="uploadform" enctype="multipart/form-data">
<input type="text" asp-for="Name" />
<input type="file" class="filepond"asp-for="photos">
<button type="submit" class="uploadbtn">Upload Document</button>
</form>
<script>
$(document).ready(function(e){
pond = FilePond.create(
document.querySelector('.filepond'), {
allowMultiple: true,
instantUpload: false,
allowProcess: false
});
$("#uploadform").submit(function (e) {
e.preventDefault();
var formdata = new FormData(this);
// append FilePond files into the form data
pondFiles = pond.getFiles();
for (var i = 0; i < pondFiles.length; i++) {
// append the blob file
formdata.append('photos', pondFiles[i].file);
}
$.ajax({
url: "/test/Index",
data: formdata,
processData: false,
contentType: false,
method:"post"
});
})
});
</script>
result:

How to send Id and file to same controller?

"i want to send id and file data to same action uploadFile(int id, httpPostFileBase upFile) ?"
i tried to send the patient id via ajax during submit, and file using name attribute in input tag.
#using (Html.BeginForm("uploadFile", "patientsProfile", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="upFile" />
<br />
<input type="submit" name="submit" value="Upload!" />
}
var id = url.substring(url.lastIndexOf('/') + 1);
$("form").submit(function (e) {
$.ajax({
type: "POST",
url: "#Url.Action("uploadFile","patientsProfile")",
data: {
Id: id
},
success: function (res) {
alert("id :" + id);
}
})
})
[HttpPost]
public ActionResult uploadFile( HttpPostedFileBase upFile , int Id)
{
Tests tests = new Tests();
tests.patients_Id = Id;
string fileName = upFile.FileName;
string UniquefileName = Guid.NewGuid() + Path.GetFileName(upFile.FileName);
string filePath = Server.MapPath("~/Uploaded/");
string actualPath = Path.Combine(filePath + UniquefileName);
upFile.SaveAs(actualPath);
tests.Name = fileName;
tests.urlName = actualPath;
db.Tests.Add(tests);
db.SaveChanges();
return RedirectToAction("index");
}
httpPostFileBase upFile be null but id take it's value correctly
First of all I think that the below code is going to cause issues
var id = url.substring(url.lastIndexOf('/') + 1);
Reasons
If it is used to get the id when the ids are only one character then it works well, but when the number of character increases it is going to get wrong values. example for a url www.yourdomain.com/controller/action/1 it will work fine, but www.yourdomain.com/controller/action/12 will return the same result as the first. So you might want to do some math there like (stringLength - lastIndexOf / )
I will suggest you use ViewBag to get that Id since it was passed from the GET method and then pass that to the form as a parameter like below
#using (Html.BeginForm("uploadFile", "Home", new{Id = ViewBag.Id}, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="upFile" id="upFile" />
<br />
<input type="submit" name="submit" value="Upload!" />
}
remember to include the view bag in the get request as
public ActionResult ActionName(int Id)
{
ViewBag.Id = Id;
return View();
}
IF you insist on using javascript then try including the file as a data like in this answer
#using (Html.BeginForm("uploadFile", "Home", new{Id = ViewBag.Id},
FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="upFile" id="upFile" />
<input type="hidden" name="hdfid" id="hdfid" value ="" />
<br />
<input type="submit" name="submit" value="Upload!" />
}
var id = url.substring(url.lastIndexOf('/') + 1);
$("#hdfid").val(id);
$("form").submit(function (e) {
$.ajax({
type: "POST",
url: "#Url.Action("uploadFile","patientsProfile")",
success: function (res) {
alert("id :" + id);
}
})
})
public ActionResult uploadFile( formcollection form, HttpPostedFileBase
upFile )
{
Tests tests = new Tests();
string id = form["id"];//or provide index
tests.patients_Id = Id;
string fileName = upFile.FileName;
string UniquefileName = Guid.NewGuid() +
Path.GetFileName(upFile.FileName);
string filePath = Server.MapPath("~/Uploaded/");
string actualPath = Path.Combine(filePath + UniquefileName);
upFile.SaveAs(actualPath);
tests.Name = fileName;
tests.urlName = actualPath;
db.Tests.Add(tests);
db.SaveChanges();
return RedirectToAction("index");
}
you have to pass the upFile to to the data which you are sending.
data: {
Id: id,
upFile: //the file which you are sending
},

Is there a way to save a single image and to prevent user put more than an image using dropzone.js?

I'm try to upload image in database, i'm using drobzone.js
that's my controller code
[HttpGet]
public ActionResult Show(int? id)
{
string mime;
byte[] bytes = LoadImage(id.Value, out mime);
return File(bytes, mime);
}
[HttpPost]
public ActionResult Upload()
{
SuccessModel viewModel = new SuccessModel();
if (Request.Files.Count == 1)
{
var name = Request.Files[0].FileName;
var size = Request.Files[0].ContentLength;
var type = Request.Files[0].ContentType;
viewModel.Success = HandleUpload(Request.Files[0].InputStream, name, size, type);
}
return Json(viewModel);
}
private bool HandleUpload(Stream fileStream, string name, int size, string type)
{
bool handled = false;
try
{
byte[] documentBytes = new byte[fileStream.Length];
fileStream.Read(documentBytes, 0, documentBytes.Length);
Pictures databaseDocument = new Pictures
{
ProfilePicture=documentBytes,
FName=name,
Size=size,
Type=type
};
using(var contxt=new EnglisCenterEntities())
{
contxt.Pictures.Add(databaseDocument);
handled = (contxt.SaveChanges() > 0);
}
}
catch (Exception )
{
// Oops, something went wrong, handle the exception
}
return handled;
}
private byte[] LoadImage(int id, out string type)
{
byte[] fileBytes = null;
string fileType = null;
using(var contxt=new EnglisCenterEntities())
{
var databaseDocument = contxt.Pictures.FirstOrDefault(doc => doc.IdPicture == id);
if (databaseDocument != null)
{
fileBytes = databaseDocument.ProfilePicture;
fileType = databaseDocument.Type;
}
}
type = fileType;
return fileBytes;
}
and this is my script
<script type="text/javascript">
$(document).ready(function () {
$("#preview").fadeOut(15);
$("#refreshButton").click(function () {
var imageToLoad = $("#imageId").val();
if (imageToLoad.length > 0) {
$("#preview").attr("src", "/Document/Show/" + imageToLoad);
$("#preview").fadeIn();
}
});
});
and this is my view
<form action="/Document/Upload" class="dropzone" id="my-awesome-dropzone"></form>
<input type="text" name="imageId" id="imageId" />
<button type="button" id="refreshButton">Update Image</button>
<img src="/" style="display: none" id="preview" />
and it's working with multi images but i want to save single image and prevent the user put more than one image. Is there a way to save a single image and to prevent user put more than an image using dropzone.js?
Javascript is needed to limit maxFiles, see http://www.dropzonejs.com/#configuration-options and http://jsfiddle.net/P2dTF/2/ for example:
Dropzone.autoDiscover = true;
Dropzone.options.my-awesome-dropzone = {
maxFiles: 1
};
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
SuccessModel viewModel = new SuccessModel();
if (file != null)
{
viewModel.Success = HandleUpload(file);
}
return Json(viewModel);
}
Param name of file is important, dropzone binds single upload to param file (and multiple to a param array of files). Don't see why you need a fileStream though, fileStream is needed when you want to return a range of bytes for example with a Request Header (audio) for partial download, HttpPostedFileBase does the job in your case.
private bool HandleUpload(HttpPostedFileBase file)
{
bool handled = false;
try
{
byte[] documentBytes = new byte[file.ContentLength];
Pictures databaseDocument = new Pictures
{
ProfilePicture=documentBytes,
FName=file.FileName,
Size=file.ContentLength,
Type=file.ContentType
};
using(var contxt=new EnglisCenterEntities())
{
contxt.Pictures.Add(databaseDocument);
handled = (contxt.SaveChanges() > 0);
}
}
catch (Exception )
{
// Oops, something went wrong, handle the exception
}
return handled;
}

AJAX: Asynchronously posting a file to a server

I want to post a file to server asynchronously without posting the form. I have the following code:
var fileInput = document.getElementById('FileInput');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('file', file, file.name);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://servername/controllername/AnalyseFile', true);
xhr.setRequestHeader('Content-Type', 'multipart/form-data');
xhr.send(formData);
However, when the method is executed on the server, the post body contains no files. The following is from ASP.NET MVC4:
[HttpPost]
public JsonResult AnalyseFile()
{
int filesCount = Request.Files.Count;
if(filesCount == 0) { throw new Exception('no files...'); }
// do stuff
}
The Files collection contains no files and I can't figure out why. Any help appreciated.
In the View, you can do:
<form>
<input name="input1" id="input1"/>
<input name="input2" id="input2"/>
<input name="input3" id="input3"/>
...
<input id="SelectedFile" name="SelectedFile" type="file"/>
</form>
And Javascript:
function AttLogic(_url, _data, _callback) {
$.ajax({
url: _url,
type: 'POST',
xhr: function () {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) { }
return myXhr;
},
data: _data,
cache: !1,
success: _callback,
contentType: !1,
processData: !1
});
}
function FormDataCustom(f) {
var __frm = jQuery(f), data = new FormData(f);
$(':disabled[name]', __frm).each(function () {
data.append(this.name, $(this).val());
});
return data;
}
function SaveLogic(){
var dt = FormDataCustom(document.forms[0]);
AttLogic(yourUrl, dt, function (r) {
//do something here
});
}
In the Controller:
public ActionResult Save(parameter1,parameter1,..., List<HttpPostedFileBase> SelectedFile)
{
//do something here
}
You will need to read the MultiPartFormData from the Request.
As per this post:
Your method will look something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace Some.Namespace
{
public class SomeController : ApiController
{
[HttpPost]
public async Task<JsonResult> AnalyseFile()
{
if (!Request.Content.IsMimeMultipartContent())
{
//If not throw an error
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider("c:\\tmp\\uploads");
// Read the MIME multipart content using the stream provider we just created.
IEnumerable<HttpContent> bodyparts = await Request.Content.ReadAsMultipartAsync(streamProvider);
// Get a dictionary of local file names from stream provider.
// The filename parameters provided in Content-Disposition header fields are the keys.
// The local file names where the files are stored are the values.
//depending on your version of .net, this might have been changed to FileData instead.
// see: https://msdn.microsoft.com/en-us/library/system.net.http.multipartformdatastreamprovider(v=vs.118).aspx
IDictionary<string, string> bodyPartFileNames = streamProvider.BodyPartFileNames;
//rest of code here
}
}
I haven't tested the above code, but it should point you in the right direction.
Also have a look at How To Accept a File POST
For a more recent article: https://code.msdn.microsoft.com/AngularJS-with-Web-API-22f62a6e

Trying to upload a file using ajax in ASP.NET MVC

I am using ASP.NET MVC 3, I want to upload a image file using an ajax form
My Index view code is:
<% using (Ajax.BeginForm("Save","Home", new AjaxOptions() { HttpMethod = "POST", InsertionMode = InsertionMode.Replace }, new { enctype = "multipart/form-data" }))
{%>
<input type="file" /><input type ="submit" value="Submit File"/>
<% } %>
and Controller code is:
[HttpPost]
public ActionResult Save()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View("Index");
}
When I upload a file and click on the button, the ajax form is submitted, but i am getting a Request.File.Count of 0.
Default unobtrusive ajax in mvc doesn't support uploading files. You need to use hidden iframe/plugin (flash, silverlight..)/html5 or combination of those.
Some scripts that might help you:
http://valums.com/ajax-upload/
http://www.uploadify.com/
You can use the the plugins suggested by #Lukáš Novotný or else you can do the following
Create an Generic HTTP handler uploadfile.ashx
Post the data to the file(set the form action="yourpath/UploadFile.ashx"
In the handler you can read the file as
HttpPostedFile uploadedfile = context.Request.Files[0];
Here's my Action that manages the file uploads. Would work with most Ajaxy file uploaders. (I think)
public ActionResult Upload(HttpPostedFileBase uploadfile)
{
try
{
var dr405 = new DR405Service().GetDR405ById(new DR405DBContext(), DR405Profile.CurrentUser.TangiblePropertyId);
var saveLocation = Path.Combine(DR405Service.SavePath + DR405Profile.CurrentUser.TangiblePropertyId);
System.IO.Directory.CreateDirectory(saveLocation);
if ((int)uploadfile.ContentLength / 1024 <= 15000)
{
uploadfile.SaveAs(Path.Combine(saveLocation, Path.GetFileName(uploadfile.FileName)));
var file = new dr405files { TangiblePropertyId = DR405Profile.CurrentUser.TangiblePropertyId, FileName = uploadfile.FileName, UploadDate = DateTime.Now };
//dr405.dr405files.Add(file);
//c.dr405s.Add(dr405);
db.Entry(file).State = file.FileId == 0 ? EntityState.Added : EntityState.Modified;
//db.Entry(dr405).State = EntityState.Modified;
new DR405Service().Save(db);
ViewData["UploadStatus"] = String.Format("File name: {0}, {1}Kb Uploaded Successfully.", uploadfile.FileName, (int)uploadfile.ContentLength / 1024);
}
else
{
ViewData["UploadStatus"] = String.Format("File exceeds 15MB upload limit. Please reduce size and try again.", uploadfile.FileName);
}
}
catch (Exception ex)
{
ViewData.ModelState.AddModelError("_FORM", ex.ToString());
}
return View();
}

Categories