MVC serialize object, list of objects, collections in Json - asp.net-mvc

Parsing json returned from the controller. For some reason when returning a dictionary I need to do "ToString()" on the key element, otherwise I get an error. Why?. Are the samples below the correct way/best way to serialize json? thanks
Controller:
// JSON
public ActionResult GizmosJsonObject()
{
var gizmo = new Gizmo
{
Id = 2343,
Name = "Some awesome name",
Quantity = 32,
IntroducedDate = DateTime.Now
};
return this.Json(gizmo);
}
public ActionResult GizmosJsonObjectCollection()
{
var gizmos = new List<Gizmo>();
gizmos.Add(new Gizmo
{
Id = 102,
Name = "some name1",
Quantity = 535,
IntroducedDate = DateTime.Now
});
gizmos.Add(new Gizmo
{
Id = 122,
Name = "some name1",
Quantity = 135,
IntroducedDate = DateTime.Now
});
gizmos.Add(new Gizmo
{
Id = 562,
Name = "some name1",
Quantity = 2,
IntroducedDate = DateTime.Now
});
return this.Json(gizmos);
}
public ActionResult GizmosJsonListInts()
{
var gizmos = new List<int>();
gizmos.Add(2);
gizmos.Add(56);
gizmos.Add(32);
return this.Json(gizmos);
}
public ActionResult GizmosJsonDictionaryInts()
{
var gizmos = new Dictionary<int, int>();
gizmos.Add(23, 123);
gizmos.Add(26, 227);
gizmos.Add(54, 94323);
return this.Json(gizmos.ToDictionary(x => x.Key.ToString(), y => y.Value));
}
public ActionResult GizmosJsonDictionaryStrings()
{
var gizmos = new Dictionary<string, string>();
gizmos.Add("key1", "value1");
gizmos.Add("Key2", "value2");
gizmos.Add("key3", "value3");
return this.Json(gizmos);
}
View:
<script type="text/javascript">
/*<![CDATA[*/
$(function () {
// json object
$("a.Object").click(function (e) {
e.preventDefault();
$.ajax({
url: '#Url.Action("GizmosJsonObject", "Home")',
contentType: 'application/json',
type: 'POST',
success: function (json) {
console.log(json.Id);
console.log(json.Name);
console.log(json.IntroducedDate);
// format date
var date = new Date(parseInt(json.IntroducedDate.substr(6)));
console.log(date);
}
});
});
// json object collection
$("a.ObjectCollection").click(function (e) {
e.preventDefault();
$.ajax({
url: '#Url.Action("GizmosJsonObjectCollection", "Home")',
contentType: 'application/json',
type: 'POST',
success: function (json) {
$(json).each(function () {
console.log(this.Id);
console.log(this.Name);
console.log(this.IntroducedDate);
// format date
var date = new Date(parseInt(this.IntroducedDate.substr(6)));
console.log(date);
});
}
});
});
// json list of ints
$("a.ListInts").click(function (e) {
e.preventDefault();
$.ajax({
url: '#Url.Action("GizmosJsonListInts", "Home")',
contentType: 'application/json',
type: 'POST',
success: function (json) {
$(json).each(function (i, e) {
console.log(json[i]);
});
}
});
});
// json dictionary of ints
$("a.DictionaryInts").click(function (e) {
e.preventDefault();
$.ajax({
url: '#Url.Action("GizmosJsonDictionaryInts", "Home")',
contentType: 'application/json',
type: 'POST',
success: function (json) {
for (var key in json) {
if (json.hasOwnProperty(key)) {
var value = json[key];
console.log(key);
console.log(value);
}
}
}
});
});
// json dictionary of strings
$("a.DictionaryStrings").click(function (e) {
e.preventDefault();
$.ajax({
url: '#Url.Action("GizmosJsonDictionaryStrings", "Home")',
contentType: 'application/json',
type: 'POST',
success: function (json) {
for (var key in json) {
if (json.hasOwnProperty(key)) {
var value = json[key];
console.log(key);
console.log(value);
}
}
}
});
});
});
/*]]>*/
</script>

A JSON key must be of the type string. See the right sidebar here http://www.json.org/ where it states that a pair must take the form of string: value.
Just for corroboration, this document here http://www.ietf.org/rfc/rfc4627.txt states the following:
2.2. Objects
An object structure is represented as a pair of curly brackets
surrounding zero or more name/value pairs (or members). A name is a
string. A single colon comes after each name, separating the name
from the value. A single comma separates a value from a following
name. The names within an object SHOULD be unique.

Related

Unable to send array data using ajax with ASP.NET Core and Entity Framework Core

I am trying to send array to the controller but it's blank in the controller parameter.
Ajax function is:
$('#pending').click(function () {
SaveTestResult("/Reception/PatientTests/SavePendingTest");
});
function SaveTestResult(url) {
var pid = $('.patientId').attr('id');
var tid = "";
var tval = "";
var tpid = "";
var tests = [];
$("table > tbody > tr").each(function () {
testId = $(this).find('.tid').val();
if (typeof (testId) != "undefined") {
tid = testId;
}
var rowText = ""
$(this).find('td').each(function () {
tpid = $(this).find('.tpId').val();
tval = $(this).find('.result').val();
if (typeof (tpid) != "undefined") {
tests.push({ PatientId: pid, TestId: tid, TestParameterId: tpid, TestValue: tval });
}
});
});
// alert(JSON.stringify(tests));
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(tests),
contentType: "application/json",
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
success: function (data) {
alert(data);
},
error: function (e) {
alert('Error' + JSON.stringify(e));
}
});
}
This is the controller method:
[HttpPost]
[Route("Reception/PatientTests/SavePendingTest")]
public async Task<IActionResult> SavePendingTest(List<PendingTestResult> pendingTestResult)
{
if (ModelState.IsValid)
{
foreach (PendingTestResult ptr in pendingTestResult)
{
_db.Add(ptr);
await _db.SaveChangesAsync();
}
// return new JsonResult("Index");
}
return new JsonResult(pendingTestResult); ;
}
But when run the code I see data array filled but inside of the SavePendingTest action, pendingTestResult is empty and not filled! I also tried the [FromBody] tag inside action params, but it does not work either!
Help me resolve this
you are sending a string with no names so the controller can not get the values.
change you code to
$.ajax({
type:"POST",
url:url,
data:test
...
});
the test should be an object not a string.
You can pass the list of objects by :
$.ajax({
type: "POST",
url: "Reception/PatientTests/SavePendingTest",
data: { pendingTestResult: tests },
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
success: function (data) {
alert(data);
},
error: function (e) {
alert('Error' + JSON.stringify(e));
}
});
pendingTestResult in data:{ pendingTestResult: tests } matches the parameter name on action and remove the contentType setting .

jquery autocomplete passing parameters

I need help to pass parameters through JQuery's autocomplete. I have an input:
<input type="text" class="form-control mb-2 mr-sm-2 mb-sm-0" name="searchName" id="searchName" placeholder="Nom et/ou prénom" />
inside a form. When you type, an jquery autocomplete function launches a search in Active Directory and shows result in the drop down list:
$(document).ready(function () {
$("#searchName").autocomplete({
source: function (request, response) {
$.ajax({
url: "/Home/SearchUserWhileTyping",
type: "GET",
data: { name: $("#searchName").val() },
contentType: "application/json;charset=utf-8",
dataType: "json",
success: function (data) {
$("#searchName").html(''),
response($.map(data, function (item) {
return {
label: item
}
}));
}
});
},
minLength: 4
})
});
$(document).ready(function(){
$('#searchName').on('autocompletechange change', function () {
$('#searchValue').html('You selected: ' + this.value);
}).change()});
For now I could only do it after a form validation: form is validated -> I load the users found and their unique id -> click on one link and it shows the user info thanks to their unique id passed through. What I want to do is: If you click on one of the autocomplete choices, it directly shows the information of your user.
Here is the code for the search while you type:
[HttpGet]
public ActionResult SearchUserWhileTyping(string name)
{
ADManager adManager = new ADManager();
List<string> lastName = adManager.SearchUserByName(name);
List<string> splitList = new List<string>();
if (lastName != null)
{
if (lastName.Count <= 10)
{
int inc = 0;
foreach(string splitter in lastName)
{
if (inc % 2 == 1)
{
splitList.Add(splitter);
}
inc++;
}
return Json(splitList, JsonRequestBehavior.AllowGet);
}
}
return null;
}
I use a splitter because another function allows me to search AD and returns several parameters (which will then be useful to immediately find a user by its unique id, that's my difficulty).
This calls the following function:
public List<string> SearchUserByName(string name)
{
try
{
DirectoryEntry ldapConnection = createDirectoryEntry();
DirectorySearcher search = new DirectorySearcher(ldapConnection);
var sidInBytes=new byte[0];
//anr permet de chercher tout utilisateur contenant "name"
search.Filter = "(&(objectClass=user)(anr=" + name + "))";
//search.Filter = "(&(objectClass=User) (name=" + name + "*))";
search.PropertiesToLoad.Add("displayName");
search.PropertiesToLoad.Add("distinguishedName");
resultCollection = search.FindAll();
if (resultCollection.Count == 0)
{
return null;
}
else
{
foreach(SearchResult sResult in resultCollection)
{
if (sResult.Properties["distinguishedName"][0].Equals(null) ||
sResult.Properties["displayName"][0].Equals(null))
continue;
displayName.Add(sResult.Properties["distinguishedName"][0].ToString());
displayName.Add(sResult.Properties["displayName"][0].ToString());
}
}
ldapConnection.Close();
ldapConnection.Dispose();
search.Dispose();
return displayName;
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return null;
}
Finally, when I have my list of users, I can click on their link and I load info about the user using this function:
public List<KeyValuePair<string,string>> GetUserInfoBySAMAN(string sAMAccountName)
{
try
{
DirectoryEntry ldapConnection = createDirectoryEntry();
DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = "(sAMAccountName=" + sAMAccountName + ")";
search.PropertiesToLoad.Add("objectSID");
search.PropertiesToLoad.Add("displayName");
search.PropertiesToLoad.Add("memberOf");
search.PropertiesToLoad.Add("description");
search.PropertiesToLoad.Add("accountExpires");
search.PropertiesToLoad.Add("sAMAccountName");
result = search.FindOne();
///Conversion du SID en chaine de caractères
var sidInBytes = (byte[])result.Properties["objectSID"][0];
var sid = new SecurityIdentifier(sidInBytes, 0);
String time;
if (result.Properties["accountExpires"][0].ToString().Equals("0")|| result.Properties["accountExpires"][0].ToString().Equals("9223372036854775807"))
{
time = "Jamais";
}
else
{
///Conversion de la date en entier puis en date
DateTime dt = new DateTime(1601, 01, 02).AddTicks((Int64)result.Properties["accountExpires"][0]);
time = dt.ToString();
}
string desc="";
if (result.Properties.Contains("description"))
{
desc = result.Properties["description"][0].ToString();
}
else
{
desc = "Pas de description disponible";
}
userInfo = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("displayName",result.Properties["displayName"][0].ToString()),
new KeyValuePair<string, string>("memberOf", result.Properties["memberOf"][0].ToString()),
new KeyValuePair<string, string>("accountExpires",time),
new KeyValuePair<string, string>("description",desc),
new KeyValuePair<string, string>("sid",sid.ToString()),
new KeyValuePair<string, string>("sAMAccountName",result.Properties["sAMAccountName"][0].ToString())
/*lastName.Add(result.Properties["displayName"][0].ToString());
lastName.Add(result.Properties["memberOf"][0].ToString());
lastName.Add(sid.ToString());
lastName.Add(result.Properties["accountExpires"][0].ToString());
lastName.Add(result.Properties["description"][0].ToString());*/
};
return userInfo;
}
catch(Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return null;
}
That last function doesn't work if I change sAMAccountName by distinguishedName because apparently this attribute cannot be used like that. I want to use distinguishedName and immediately have my object.
So what I need is to search while I type, and if I select one of the proposed choices, validating the form immediately send me to user info page.
Thanks for your help, hope it is clear enough
Edit I added a 2nd script that can get the value of selected item, but I need the data passed through the controller
If I understood right, autocomplete method has select event.
$(document).ready(function () {
$("#searchName").autocomplete({
source: function (request, response) {
$.ajax({
url: "/Home/SearchUserWhileTyping",
type: "GET",
data: { name: $("#searchName").val() },
contentType: "application/json;charset=utf-8",
dataType: "json",
success: function (data) {
$("#searchName").html(''),
response($.map(data, function (item) {
return {
label: item
}
}));
},
select: function(e, ui)
{
//Just Example
$.get("UserController", {ID: ui.Id}).done(
function(data){
});
//Write your ajax post or get method
//that fetches user data directly as soon as
//the item in list clicked
}
});
},
minLength: 4
})
});
Edit: I saw your edit, so that you can use your GetUserInfoBySAMAN function for ajax get request inside select event (instead where I wrote "UserController"), and you have work for binding return data to the inputs or labels as well.

How can get image with Jquery Ajax

I can can get picture by Razor '#Action' but with Ajax Can't. I write
in controller:
public ActionResult getCommodityPic()
{
var f= File(Server.MapPath("~/App_Data/CommodityPics/eee/1") + ".jpg", "image/jpg");
return f;
}
and in java script :
$(document).ready(function () {
ShowCommodities();
getCommodityPic();
});
function getCommodityPic() {
$.ajax({
url: '#Url.action("getCommodityPic")',
type: 'Get',
dataType: 'image/jpg',
success: function (Data, Status, jqXHR) {
$('#img1').attr('src', Data);
}
});
$.ajax({
url: '#Url.Action("DownloadPic", "MyController")',
contentType: 'application/json; charset=utf-8',
datatype: 'json',
data: {
id: Id
},
type: "GET",
success: function (Data, Status, jqXHR) {
if (Data != "") {
alert("Empty");
return;
}
window.location ='#Url.Action("DonloadPic","Mycontroller")';
}
});
in Controller:
public ActionResult DownloadPic(int? id)
{
Lesson l = new Lesson();
l = db.Lesson.Single(p => p.id == id);
if (l.picture == null)
{
string targetFolder = System.Web.HttpContext.Current.Server.MapPath("~/Image/book-03.jpg");
byte[] img = System.IO.File.ReadAllBytes(targetFolder);
return File(img, "image/jpg");
}
return File(l.picture, "image/jpg");
}
If you want to display the image dynamically, then try this. You may not need an Ajax call for this.
$('#img1').html('<img src="getCommodityPic" />')
If you want to process the image (read its raw binary) then this answer should help - https://stackoverflow.com/a/20048852/6352160

observableArray sent as parameter to a contoller function is null

I want to pass the data in the FeatureList (observableArray) to the SaveMappings function in the TreeController. I have binded a button to the sendItems function. I put a breakpoint at the var data=p2fData line to see what I received. p2fData is null.
I changed the controller to public JsonResult SaveMappings(List p2fData). In this case p2f data shows that there is 1 element, but then its null too.
var Feature = function (featId) {
var self = this;
self.featId = featId;
self.parameters = ko.observableArray();
}
var ParameterToFeatureListViewModel = function () {
var self = this;
var newFeature = new Feature("Feature XYZ");
newFeature.parameters.push("1");
newFeature.parameters.push("2");
self.FeatureList = ko.observableArray([newFeature]);
self.sendItems = function() {
$.ajax({
type: "POST",
url: '/Tree/SaveMappings',
data: ko.toJSON(self.FeatureList),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
alert(response);
},
error: function (request, status, error) {
alert(request.statusText);
}
});
}
}
var vm = new ParameterToFeatureListViewModel()
ko.applyBindings(vm);
public class TreeController:Controller
{
public ActionResult Index(){...}
[HttpPost]
public JsonResult SaveMappings(string p2fData)
{
var data = p2fData;
return Json(data);
}
}
Please have a look # how to pass knockoutjs view model into a mvc controller
... May be it helps..

Pass raw html from view to controller

I want to pass raw html from view to controller. Iam trying to do it with jquery ajax request. Everything is ok until object with raw html passes to controller. What is my mistake?
Here is my model, controller and jquery.
Thank you.
Model
public class NewsEditionModel
{
public string Title { get; set; }
public string SubTitle { get; set; }
public string Text { get; set; }
}
Controller
public ActionResult AddText(NewsEditionModel obj)
{
var news = new News();
try
{
news.Text = obj.Text;
news.PublishDate = DateTime.Now;
news.Title = obj.Title;
var repository = new Repository();
var success = repository.AddNews(news, User.Identity.Name);
return Json(new {data = success});
}
catch (Exception)
{
return View("Error");
}
}
Jquery
function submitForm() {
var text = ste.getContent();
var title = $('#title').val();
var obj1 = JSON.stringify({ Text: text, Title: title, SubTitle: "" });
var obj = $.parseJSON(obj1);
$.ajax({
type: "POST",
dataType: "json",
content: "application/json",
data: {obj: obj},
url: '#Url.Action("AddText", "News")',
success: function (res) {
}
});
}
Just add <ValidateInput(False)> _ to your contoller post req.
You can use this example
$.ajax({
url: '#Url.Action("AddText", "News")',
data: {obj: JSON.stringify({ Text: text, Title: title, SubTitle: "" })},
contentType: 'application/json',
dataType: 'json',
success: function (data) { alert(data); }
});
I guess instead of this:
data: {obj: obj},
you should do it like this:
data: {obj: JSON.stringify({ Text: text, Title: title, SubTitle: "" })},

Resources