FormData key does not go through - c#

I use external class for making object variable into FormData variable. All of the keys go through, all but One for File object.
Here is that external class: https://github.com/therealparmesh/object-to-formdata
This is how I create objects and make them into FormData
var _documents = [];
for (var i = 0; i < arrayOfFiles.length; i++) {
var document = {
File: arrayOfFiles[i].file.nativeFile,
DocumentId: arrayOfFiles[i].documentId,
DocumentType: arrayOfFiles[i].documentName
};
_documents.push(document);
}
var uploadedInformation = {
LoanID: 1452465,
documents: _documents
};
var options = {
indices: true,
nulls: true
};
var a = objectToFormData(uploadedInformation, options);
for (var pair of a.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
jQuery.ajaxSettings.traditional = true;
$.ajax({
async: false,
cache: false,
contentType: false,
processData: false,
type: 'POST',
url: '#Url.Action("UploadFile", "Home")',
data: a
});
Code for controller:
[HttpPost]
[ActionName("UploadFile")]
public ActionResult UploadFile(UploadedInformation uploadedInformation)
{
_ = Request.Form;
return View();
}
UploadedFile class:
public class UploadedInformation
{
public long LoanID { get; set; }
public IEnumerable<Document> Documents { get; set; }
}
Document class:
public class Document
{
public HttpPostedFileBase File { get; set;}
public string DocumentId { get; set;}
public string DocumentType { get; set; }
}
All of the items bind perfectly, except for File.
In browser debugger keys and values are:
LoanID, 1452465
documents[0][File], [object File]
documents[0][DocumentId], 1
documents[0][DocumentType], Passport
_=Request.Form also displays only 3 keys without documents[0][File]
Update:
I changed controller to
public ActionResult UploadFile(IEnumerable<HttpPostedFileBase> file, IEnumerable<string> documentType, IEnumerable<string>documentId, long loanId){...}
and _=Request.Form still shows nothing with file, however file list is populated
Another update:
Apparently, this time file items shows only in _=Request.File

Due to the way that the controller is handling the file upload parts of the request, I suspect you may need to make some adjustments to your process and allow for the fact that the files are being separated from the main object.
I've included some adjustments to your code below (note, this is untested so you may need to experiment a little), assuming that the files come through in the same order as you Documents, then just run a match up process before running your own process.
Code for controller:
[HttpPost]
[ActionName("UploadFile")]
public ActionResult UploadFile(List<HttpPostedFileBase> myFiles, UploadedInformation uploadedInformation)
{
for (var i = 0; i <uploadedInformation.Documents.Length; i++)
{
uploadedInformation.Documents[i].File = myFiles[i];
}
// Do stuff
return View();
}
In the event that the order of the files cannot be assumed, you can add the filename to the data to aid with matching on the server side
Javascript
var _documents = [];
for (var i = 0; i < arrayOfFiles.length; i++) {
var document = {
File: arrayOfFiles[i].file.nativeFile,
FileName: arrayOfFiles[i].file.name,
DocumentId: arrayOfFiles[i].documentId,
DocumentType: arrayOfFiles[i].documentName
};
_documents.push(document);
}

Related

Ajax send array and bool to controller method

I've been trying to send an array of objects to a controller method using AJAX, but even after trying various methods I still won't get my desired result. This is my current code:
View
function SaveGame() {
if ('#Session["Username"]' == '#Model.Player1.Username') {
p1 = true;
}
else {
p1 = false;
}
var characters = document.getElementsByClassName("char");
var chardata = [];
for (var i = 0; i < characters.length; i++) {
var id = characters[i].id;
var state = characters[i].classList[1];
chardata.push(id, state);
}
console.log(chardata);
$.ajax({
url: '#Url.Action("SaveGame", "Game")',
type: 'GET',
data: JSON.stringify({ 'character': chardata }),
cache: false,
contentType: 'application/JSON',
success: function (result) {
alert("Game Saved");
}
});
}
Gamecontroller/SaveGame
public bool SaveGame(JsonDecode character)
{
ViewGame game = (ViewGame)TempData["game"];
TempData["game"] = game;
return true;
//return charLayer.SaveCharacters(game.Id, ids, states, isPlayer1);
}
character will just be null
JsonDecode
public class JsonDecode
{
public object[] chardata { get; set; }
}
Your current code is using GET as the type for the $.ajax call. jQuery ajax will issue a GET request to the endpoint with the data appended to the querystring of the URL it is making the call to. When you want to send simple values, it is fine, but when you want to send a complex object like what you want to send, you should use POST type.
Also, for model binding to work, the structure of the data should be similar to your view model structure and property names. Based on the data you want to send, looks like you need a view model like this.
public class GameStateVm
{
public int Id { set;get;}
public string State { set;get;}
}
public class SaveGameVm
{
public GameStateVm[] Character { set;get;}
public bool PFlag { set;get;}
}
which you can use as the parameter of your HttpPost action method.
[HttpPost]
public ActionResult SaveGame(SaveGameVm characters)
{
// I am simply returning the posted data as it is, for testing
// You may return a boolean value if you want that.
return Json(characters);
}
and now in your client side code, make sure your JS object has similar strucutre and property names.
// JS object with same structure as our SaveGameVm
var d = { PFlag: false, character:[]};
d.PFlag = true; // to do : Set the value based on your condition
// dummy code to add 2 items to the array.
// to do : replace with your code to populate the array
for (var i = 0; i < 2; i++) {
var id =i; // to do : replace hard coded values
var state = 'active';
d.character.push({ id: id, state: state});
}
$.ajax({
url: '#Url.Action("SaveGame", "Game")',
type: 'POST',
data: JSON.stringify(d),
contentType: 'application/JSON',
success: function (result) {
console.log(result);
}
});

Retrieving data appended to formData in C#

In this scenario:
var xhr = new XMLHttpRequest();
var fd = new FormData();
fd.append("file", document.getElementById('fileUpload').files[0]);
fd.append("PhoneId", '1234');
xhr.open("POST", '/Main/Upload', true);
xhr.send(fd);
xhr.addEventListener('load', function (event) {
var test = event.target.response;
})
I have a file upload along with an integer attached. My controller is:
public ActionResult Upload(Model newModel)
{
NewFiles files = new NewFiles ();
try
{
HttpPostedFileBase file = Request.Files[0];
}
catch(Exception)
{}
}
public class newModel
{
public int FileID { get; set; }
public string ReturnAction { get; set; }
public HttpPostedFileBase fileUpload { get; set; }
public int PhoneId { get; set; }
}
The uploaded file gets recognized, but what do I need in C# to view the uploaded PhoneId?
Your syntax is a bit off in the controller and won't compile. Changing the controller to the following syntax should work. This shows how to access the POSTed file and the model properties.
[HttpPost]
public ActionResult Upload(newModel model, HttpPostedFileBase file)
{
// Check the file is valid.
if (file == null || file.ContentLength == 0 || string.IsNullOrEmpty(file.FileName))
ModelState.AddModelError("fileUpload", "Invalid file uploaded.");
// Access model properties as you wish, like this:
int phoneID = model.PhoneId;
return null;
}
A couple of extra things to improve your code:
Generally speaking, when defining a class, the name of it should be in the format of CapitalizeEachWord.
It would be a lot easier if you used jQuery for your AJAX request rather than the normal JavaScript way of doing it. By using the normal JavaScript way, you're having to manually assign form properties to a FormData object, wheras with jQuery you can simpily do $("#formID").serialize().
it will work
string phoneId = Request.Form.Get("PhoneId");

c# class to knockout.js mapping

i would like to convert each object from my class to observablearray,
My model is something like this :
public class Project
{
public string Soid { get; set; }
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string ProjectTitle { get; set; }
private List<SelectedMembersForTestimonialsModel> _selectedMembersForProject;
public List<SelectedMembersForTestimonialsModel> SelectedMembersForProject
{
internal set { _selectedMembersForProject = value; }
get { return _selectedMembersForProject ?? (_selectedMembersForProject = new List<SelectedMembersForTestimonialsModel>()); }
}
}
TO convert whole class to observablearray,, i tried like this :
var RatingAndTestimonials = function () {
//Make the self as 'this' reference
var self = this;
self.projects = ko.observableArray([]);
Load Data from server to self.projects
//Function to Read All Modules datas
function GetRatingandTestimonialsData(module) {
$.ajax({
type: "POST",
url: "Home.aspx/GetRatingandTestimonialsInfos",
data: "{module : '" + module + "'}",
dataType: "json",
contentType: "application/json",
success: function (response) {
self.PageLoading = ko.observable("none");
$.each(response.d, function (i, data) {
self.projects(data.Projects);
});
}
});
}
to convert each of property from project to observablearry, (specially nested list called :SelectedMembersForProject)
i wrote following things using ko.mapping
var rt = new RatingAndTestimonials();
ko.applyBindings(ko.mapping.fromJS(rt));
but it is not working, can anyone solve my problem?
For a screen I'm working on I pass the model to my .cshtml view first, so:
#model Your.Namespace.Project
Then, in the <script> on the .cshtml view
// serialize model to json
var data = #Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model));
// "Project" being the name of the knockout VM
var vm = new Project(data);
ko.applyBindings(vm);
// definition of project knockout VM
function Project(data) {
// Data
var self = this;
ko.mapping.fromJS(data, {}, self);
}
Now all of your properties are observables, and your lists are observable arrays
Whilst you haven't said what exactly is wrong, you are not adding each project to your view model's array, you are setting the property to that project. You need to use push to add each project to the array:
$.each(response.d, function (i, data) {
self.projects.push(data.Projects);
});

Post Array as JSON to MVC Controller

I have been struggling to find a solution to this problem.
In my code, I am building up an array of an object;
var $marks = [];
var mark = function ( x, y, counter ){
this.x = x;
this.y = y;
this.counter = counter;
}
$marks.push(new mark(1, 2, 0));
$marks.push(new mark(1, 2, 1));
$marks.push(new mark(1, 2, 2));
Now I want to post this data to a MVC controller, so I would think that the data type in the controller would be a List<Mark> Marks or an array of Marks.
To post the data, I have tried;
var json = JSON.stringify($marks);
$.post('url', json).done(function(data){ /* handle */ });
OR
var json = { Marks: $marks };
$.post('url', json).done(function(data){ /* handle */ });
The second way, when looking at the data posted, looks like this
Marks[0][x]: 1
Marks[0][y]: 2
Marks[0][counter]: 0
Marks[0][x]: 1
Marks[0][y]: 2
Marks[0][counter]: 1
Marks[0][x]: 1
Marks[0][y]: 2
Marks[0][counter]: 2
But I am not sure how to translate this into a strongly typed object in the controller?
My Controller looks like this;
[HttpPost]
public ActionResult JsonSaveMarks(List<Mark> Marks){
// handle here
}
My Mark class looks like this;
public class Mark{
public string x { get; set; }
public string y { get; set; }
public string counter { get; set; }
}
I have read through other similar problems about creating a custom JsonFilterAttribute, or using the System.Web.Script.Serialization.JavaScriptSerializer class, but I cant get anything to work
Is there something obvious I am missing here? Have I got the DataType in the controller completely wrong? How can I convert this data posted into a strongly typed object?
Many Thanks
$.post() doesn't allow you to set the content type of your AJAX call - you might find (if you use Fiddler) that your Json string is being sent with a content-type of "application/x-www-form-urlencoded" (the default setting) which then causes Asp.Net MVC to incorrectly interpret your data packet.
Can you try using $.ajax() instead, and set the content type to "application/json"?
http://api.jquery.com/jQuery.ajax/
#SteveHobbs has the right answer here. On the other hand, you should JSON.stringify the JavaScript payload as you did. If you do it the other way, you will get an exception telling something like "Invalid JSON primitive" while deserializing the data coming in.
Here is the complete solution to your sample:
$.ajax({
url: '/home/index',
type: 'POST',
data: JSON.stringify($marks),
dataType: 'json',
contentType: 'application/json',
success: function (data, textStatus, jqXHR) {
console.log(data);
}
});
This code fixed my problem:
C# classes:
public class MediaAccountContent
{
public Guid IdMedia { get; set; }
public string Value { get; set; }
}
public class User
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public List<MediaAccountContent> MediaAccountContents { get; set; }
}
MVC action:
public ActionResult SavePlace(User user)
{
return Content("OK");
}
Javascript:
var mediaAccountsJson = [];
for (var i = 0; i < 10; i++)
{
mediaAccountsJson.push({
IdMedia: i,
Value: "AAA" + i
});
}
var datatItem =
{
Firstname: "Test Firstname",
Lastname: "Test Lastname",
MediaAccountContents: mediaAccountsJson
};
$.ajax({
type: "POST",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(datatItem),
url: urlAction,
success: function (status) {
}
});
Make the changes you need for your scenario and enjoy! :)

How to retrieve mongo db object and return it as json object

Hi I have this as one of my controllers:
[HttpPost]
public JsonResult GetPinPoints(string Id)
{
Frames rslt = null;
string connString = ConfigurationManager.ConnectionStrings["MongoConnStringNew"].ToString();
MongoUrl murl = new MongoUrl(connString);
MongoServer mgconf = new MongoServer(murl);
try
{
mgconf.Connect();
MongoDatabase frmlydb = mgconf.GetDatabase("framely");
MongoCollection<Frames> collection = frmlydb.GetCollection<Frames>("Frames");
ObjectId oid = new ObjectId(Id);
Frames frms = collection.FindOne(Query.EQ("_id", oid));
if (frms != null)
{
rslt = frms;
}
}
catch (Exception ex)
{
}
finally
{
mgconf.Disconnect();
}
return Json(rslt.CoordinatesObj.ToJson());
}
The mongo object looks like this:
{"MetaTagsObj":{"Meta1":"my fam","Meta2":"lololo","Meta3":"lulz"},"PictureID":"http://framely.s3.amazonaws.com/0b7a9a72-c61b-4dec-a814-40b003072e31.jpg","UserID":"1","CoordinatesObj":[{"Position":1,"Top":182,"Left":20,"Height":73,"Width":90},{"Position":2,"Top":69,"Left":103,"Height":98,"Width":1...
I use an ajax jquery function to call the controller that looks like this:
$("#mybutton").click(function(){
$.ajax({
url: '/Member/GetPinPoints',
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function(data) {
alert(data);
},
error: function() {
alert("error");
}
});
return false;
});
I dont think I am doing this right, I think it has to do with the way I return the json object. I keep getting this error:
{"Object reference not set to an instance of an object."}
right where I am returning the Json object.
The return Json(myObject) statement should take an object that'll be serialised to JSON then returned to the browser as a string, but by calling ToJson() the rslt.CoordinatesObj object will be serialised twice.
It's also possible CoordinatesObj isn't being deserislised properly, so it's throwing an exception because ToJson() is called on a null object.
The Frames class should look something like this to handle deserialising the CoordinatesObj array:
public class Frames
{
IEnumerable<Coordinate> CoordinatesObj { get; set; }
public class Coordinate
{
int Position { get; set; }
int Top { get; set; }
int Left { get; set; }
int Height { get; set; }
int Width { get; set; }
}
}
If FindOne doesn't find a matching document it returns null, so in your code sample it is entirely possible for the "rslt" variable to be null.
Also:
no need to call Connect, the driver connects automatically
dont' call Disconnect, it interferes
with connection pooling

Categories