35385

How to send uploaded file(s) via HttpPostedFileBase along with a ViewModel?

I have a huge data object within which should map to a view model through controller parameter. I also have a list of files (photos) that i need to capture within an array in the aforementioned data object.

My Model:

public class TestPerson { public int Id { get; set; } public string Name { get; set; } public string Place { get; set; } public int Age { get; set; } public byte[] File { get; set; } //[FileSize(10240)] //[FileTypes("jpg,jpeg,png")] //public HttpPostedFileBase File { get; set; } }

My Controller Method:

public void SavePersonData(HttpPostedFileBase personPhoto, TestPerson person) { var dataObject = Request.Form["person"]; var serializer = new JavaScriptSerializer(); TestPerson personReport = serializer.DeserializeObject(dataObject, typeOf(TestPerson)); System.Console.WriteLine("dummy line"); }

My .cshtml page:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> <script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script> <div id="testKo"> Name: <input type="text" data-bind="value: Name"/> Place: <input type="text" data-bind="value: Place" /><br /> Age: <input type="text" data-bind="value: Age" /><br /> <input type="button" id="submitForm" class="btn-lg" value="Submit" /> </div> <form id="photoForm" method="post" enctype="multipart/form-data"> <input type="hidden" id="personId" name="person" /> <input type="file" id="personPhotoId" name="personPhoto" /> </form> <script> $(document).ready(function () { $(document).ready(function () { var element = document.getElementById("testKo"); ko.applyBindings(viewModel, element); $("#submitForm").on("click", function () { var vmData = ko.toJSON(viewModel); //$("#personId").val({ person: vmData }); var formData = new FormData($("#photoForm")[0]); formData.append("person", vmData, "person"); //var data = new FormData(); //data.append("vmData", vmData); //data.append("photo", $("#personPhoto").get(0).files[0]) $.ajax({ type: "POST", url: '@Url.Action("SavePersonData", "Home")', //cache: false, //async: false, contentType: false, processData: false, enctype: "multipart/form-data", dataType: "json", //data: { // testPerson: vmData //}, //data: { // personPhoto: formData, // person: vmData //}, data: formData, success: function (data) { alert("success!"); } }); }); }); function generatedViewModel() { var self = this; self.Id = ko.observable("1"); self.Name = ko.observable(); self.Place = ko.observable(); self.Age = ko.observable(); self.File = ko.observable(); } var viewModel = new generatedViewModel(); }); </script>

Is there any way i can receive both the parameters in my controller action method with this code? Or do i need to tweak it in any way? I just need to send all the content including file / image upload data and non-form data object to my controller method.

Any help would be greatly appreciated!.

Answer1:

Well, the best solution for this would be to make 2 synchronized ajax calls one within the other. Send the "personPhoto" data first and then convert it into byte array and set it as a Session variable and in the success event of this ajax call, make another ajax call to the main method where you process the Form / Model data and use the cached session object for the "personPhoto".

Replace your ajax code with the following:

var data = new FormData($("#photoForm").get(0)); $.ajax({ type: "POST", url: '@Url.Action("CacheUploads", "Home")', data: data, processData: false, contentType: false, dataType: "json", success: function () { var vmData = ko.toJS(viewModel); $.ajax({ type: "POST", url: '@Url.Action("SavePersonData", "Home")', data: { person: vmData }, success: function (data) { } }); } });

And replace your controller methods with the following:

public void SavePersonData(TestPerson person) { // You no longer need to deserialize as you'll have data properly mapped to the TestPerson object. //var dataObject = Request.Form["person"]; //var serializer = new JavaScriptSerializer(); //object personReport = serializer.DeserializeObject(dataObject); person.File = (byte[])Session["UploadedPhoto"]; System.Console.WriteLine("dummy line"); } public JsonResult CacheUploads(HttpPostedFileBase personPhoto) { byte[] photoAsBytes = null; using (var binaryReader = new BinaryReader(personPhoto.InputStream)) { photoAsBytes = binaryReader.ReadBytes(personPhoto.ContentLength); } Session.Add("UploadedPhoto", photoAsBytes); return Json(new { success = true }, JsonRequestBehavior.AllowGet); }

There is no other way you can handle FormData and Non-Form ViewModel data together in a single ajax call. This is the closest I can get from a solution perspective. Good Luck!.

Answer2:

use this.

@using (Html.BeginForm("Action", "Controller", System.Web.Mvc.FormMethod.Post, new { @id = "formid", enctype = "multipart/form-data" })) { @Html.AntiForgeryToken() <input type="hidden" id="personId" name="person" /> <input type="file" id="personPhotoId" name="personPhoto" /> <input type="submit" id="submitForm" class="btn-lg" value="Submit" /> }

Recommend

  • Issue In Converting to lower Case in JQuery while fetching values from dynamic textbox [closed]
  • Using jQuery UI Themes with ASP.Net Controls
  • Observable not getting Refreshed on Submit ? knockoutjs(Fiddle Provided)
  • PowerBi embed dashboard using JavaScript
  • JSON objects and Javascript Objects
  • How to Force Bootstrap Navbar Fix To Top Push Down(slide) Elements Under
  • How to fix unexpected column order in bootstrap 4?
  • Updating related entities in an ASP.NET MVC application using Entity Framework
  • Error: Bootstrap's JavaScript requires jQuery
  • Backbone not defined with require js
  • how to make directive in angular of owl carousel?
  • How to use jQuery in a Knockout.js Template?
  • How to split an image responsive into two div blocks using css?
  • in this page hover is not working i dont know why and also footer is not taking 100% width even thou
  • Why does IE8 fail to resolve my JQuery selector for a checked radio option?
  • NHibernate proxyexception
  • Responsive Form on top of Responsive Image? - Bootstrap
  • D3 get axis values on zoom event
  • Installing iPhone App to iPhone
  • Custom validator control occupying space even though display set to dynamic
  • JSON response opens as a file, but I can't access it with JavaScript
  • Could not find rake using whenever rails
  • Cannot resolve symbol 'MyApi'
  • req.body is undefined - nodejs
  • Modifying destination and filename of gulp-svg-sprite
  • Importing jscolor library in angular 2
  • jQuery tmpl and DataLink beta
  • jqPlot EnhancedLegendRenderer plugin does not toggle series for Pie charts
  • bootstrap to use multiple ng-app
  • How to get icons for entities from eclipse?
  • How to disable jQuery.jplayer autoplay?
  • CSS Applying specific rule for a specific monitor resolution with only CSS is posible?
  • Setting background image for body element in xhtml (for different monitors and resolutions)
  • Turn off referential integrity in Derby? is it possible?
  • apache spark aggregate function using min value
  • JaxB to read class hierarchy
  • Observable and ngFor in Angular 2
  • How to Embed XSL into XML
  • UserPrincipal.Current returns apppool on IIS
  • Conditional In-Line CSS for IE and Others?