I'm making my first simple project that uses relationships, a pretty simple checklist app. I'm trying to save a ItemList with title, and it contains a collection of items (Item name and item qty) that I'm using a different model for. When I try to post from my form, I get the following modelstate error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'BringIt.Models.Item' because the type requires a JSON object (e.g.
{"name":"value"}) to deserialize correctly.
To fix this error either
change the JSON to a JSON object (e.g. {"name":"value"}) or change the
deserialized type to an array or a type that implements a collection
interface (e.g. ICollection, IList) like List that can be
deserialized from a JSON array. JsonArrayAttribute can also be added
to the type to force it to deserialize from a JSON array. ↵Path
'item', line 1, position 46." Name
I've tried to change the types in my VM and models, but can't get past this error. Here is my existing code:
Models:
namespace BringIt.Models {
public class ItemList {
public int Id { get; set; }
public string Title { get; set; }
public DateTime EventDate { get; set; }
public ICollection<Item> Items { get; set; }
}
}
namespace BringIt.Models {
public class Item {
public int Id { get; set; }
public string ItemName { get; set; }
public int ItemQty { get; set; }
public string Person { get; set; }
public ItemList ItemList { get; set; }
}
}
My VM
namespace BringIt.ViewModels {
public class AddItemsVM {
public Item item { get; set; }
public ItemList itemList { get; set; }
}
}
Client Side Controller
export class CreateItemListController {
public itemList = null;
public item;
public items = [];
public addNew() {
var item = {};
this.items.push(item);
}
public save() {
this.itemListService.save(this.itemList, this.items).then(() => { this.$location.path('/') });
}
constructor(
private itemListService: MyApp.Services.ItemListService,
private $location: angular.ILocationService
) {
Server Side Controller
namespace BringIt.API
{
public class ItemListController : ApiController {
private IEFRepository _repo;
public ItemListController(IEFRepository repo) {
this._repo = repo;
}
public IHttpActionResult Post(AddItemsVM data) {
if (!ModelState.IsValid) {
return BadRequest(this.ModelState);
}
var itemList = data.itemList;
var item = data.item;
_repo.SaveItem(itemList, item);
return Created("", itemList);
}
}
}
Repo
public void SaveItem(ItemList listToSave, Item items) {
if (listToSave.Id == 0) {
listToSave.EventDate = DateTime.Now;
_db.ItemLists.Add(listToSave);
_db.Items.Add(items);
_db.SaveChanges();
} else {
var original = _db.ItemLists.Find(listToSave.Id);
original.Title = listToSave.Title;
original.EventDate = listToSave.EventDate;
original.Items = listToSave.Items;
_db.SaveChanges();
}
}
}
The client-side service
namespace MyApp.Services {
export class ItemListService {
private ItemListResource;
public save(itemList, items) {
debugger;
var data: any = {}
data.itemList = itemList;
data.item = items;
return this.ItemListResource.save(data).$promise;
}
constructor($resource: angular.resource.IResourceService) {
this.ItemListResource = $resource('/api/itemList/:id');
}
}
angular.module('MyApp').service('itemListService', ItemListService);
Thanks for all help. I've been at this for too many hours and just can't crack it.
From the client you'll be sending a JSON message like:
{
"itemList": {},
"item": [{blah}, {blah}... ]
}
where item is a JSON array.
Your C# view model doesn't have an enumerable item property. The deserializer cannot assign an array of items to non-enumerable property. The error message you receive is accurate, but a little confusing if you're not used to the terminology!
I might recommend you remove some of the DB code from the question, because that's a different matter entirely.
Related
I have a list of objects in below json format. I would like to deserialize using below code. It is throwing unable to convert to object error. I have tried below three options, but didnt help. jsoninput is a IEnumerable<string>converted into json object using ToJson().
Error:
{"Error converting value \"{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false,\"userType\":0,\"profilePrivacy\":1,\"chatPrivacy\":1,\"callPrivacy\":0}\" to type 'Api.Models.UserInfo'. Path '[0]', line 1, position 271."}
var requests1 = JsonConvert.DeserializeObject<UsersInfo>(jsoninput);
var requests2 = JsonConvert.DeserializeObject<IEnumerable<UserInfo>>(jsoninput);
var requests3 = JsonConvert.DeserializeObject<List<UserInfo>>(jsoninput);
//Below are my classes,
public class UsersInfo
{
public List<UserInfo> UserInfoList { get; set; }
public UsersInfo()
{
UserInfoList = new List<UserInfo>();
}
}
public class UserInfo
{
public string Id { set; get; }
public string Name { set; get; }
public string LastName { set; get; }
public string ProfilePictureUrl { set; get; }
public string SmallUrl { set; get; }
public string ThumbnailUrl { get; set; }
public string Country { set; get; }
public bool IsInvalid { set; get; }
}
Below is my json object,
["{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}","{\"id\":\"318c0885-2720-472c-ba9e-1d1e120bcf65\",\"name\":\"locomotives\",\"lastName\":\"riddles\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}"]
Looping through individual items in json input and if i deserialize it like below, it works fine. But i want to deserialize the list fully. Note: jsoninput was a IEnumerable<string> before i convert in json object.
foreach (var re in jsoninput)
{
var request0 = JsonConvert.DeserializeObject<UserInfo>(re);
}
Please look at this fiddle: https://dotnetfiddle.net/XpjuL4
This is the code:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
//Below are my classes,
public class UsersInfo
{
public List<UserInfo> UserInfoList { get; set; }
public UsersInfo()
{
UserInfoList = new List<UserInfo>();
}
}
public class UserInfo
{
public string Id { set; get; }
public string Name { set; get; }
public string LastName { set; get; }
public string ProfilePictureUrl { set; get; }
public string SmallUrl { set; get; }
public string ThumbnailUrl { get; set; }
public string Country { set; get; }
public bool IsInvalid { set; get; }
}
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
Option1();
Option2();
}
public static void Option1(){
string json = #"{""UserInfoList"":[
{""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
{ ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
]}";
var obj = JsonConvert.DeserializeObject<UsersInfo>(json);
obj.UserInfoList.ForEach(e => Console.WriteLine(e.Id));
}
public static void Option2(){
string json = #"[
{""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
{ ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
]";
var obj = JsonConvert.DeserializeObject<List<UserInfo>>(json);
obj.ForEach(e => Console.WriteLine(e.Id));
}
}
Both work, and are basically very close to what you are doing. You can either serialize it as a list (based on your json, I think that's the closest to your use case, and that's Option 2).
However, put extra attention to the JSON. I had to re-parse your JSON to make it work (https://jsonformatter.org/json-parser is a nice website to do it). For the sake of explaining the example, in C#, # means raw string, and in raw string, quotes are escaped with double quotes "".
I would expect that the business logic generating this JSON is not correct, if the JSON you pasted is the direct result from it.
EDIT
Given the OP's comment:
Thanks Tu.ma for your thoughts. The other method returns
IEnumerable which is nothing but
Dictionary.Where(x => x.Value == null).Select(x =>
x.Key).ToHashSet(). The values in Dictionary are -> Key
is String, Value is UserInfo object serialized. So, in that case i
should deserialize one by one? If not, i should serialize entire list
in one shot? Am i right? – Raj 12 hours ago
The problem is in the way you are generating the list of UsersInfo. The result from Dictionary<string,string>.Where(x => x.Value == null).Select(x =>
x.Key).ToHashSet() is a bunch of strings, not of objects, so you need to serialize them one by one.
If you are worried about the linearity of the approach, you could consider running through it in parallel. Of course, you need to judge if it fits your application.
var userInfoStrings = Dictionary<string,string>.Where(x => x.Value == null).Select(x => x.Key).ToHashSet();
var UserInfoList = userInfoStrings.AsParallel().Select (u => JsonConvert.DeserializeObject<UsersInfo>(u)).ToList();
I have a problem with empty JSON lists deserializing to null while null values deserializes to an empty list.
Using this test scenario in a completely new MVC project:
public class TestController : Controller
{
public ActionResult Index(ImportObject importObject)
{
return Content("Response");
}
public class ImportObject
{
public List<string> StringListNull { get; set; }
public List<string> StringListEmpty { get; set; }
public List<string> StringListPopulated { get; set; }
}
}
I'm posting the following JSON:
{
"StringListNull": null,
"StringListEmpty": [],
"StringListPopulated": ["one", "two"]
}
And this happens:
The populated string list is expected. But in my mind the null value of StringListNull should result in it being null.
When passing the value [] I'm expecting it being turned into an empty list
Am I missing something trivial? How can I make the null value become a nulled list and the empty list become an empty list?
What controls the default serialization from JSON to the parameter class (ImportObject)?
/K
I tried your code and works absolutely fine, probably you are switching the StringListNull and StringListEmpty.
Here is how I tested it, try it out and see where you are making something wrong:
public class ImportObject
{
public List<string> StringListNull { get; set; }
public List<string> StringListEmpty { get; set; }
public List<string> StringListPopulated { get; set; }
}
class Program
{
static void Main(string[] args)
{
var sb = new StringBuilder();
var line = string.Empty;
while (!string.IsNullOrWhiteSpace((line = Console.ReadLine())))
{
sb.AppendLine(line);
}
var json = sb.ToString().Trim();
var inputObj = JsonConvert.DeserializeObject<ImportObject>(json);
Console.WriteLine();
}
}
This is a simple Console app to test your logic.
Edit:
tested with your input JSON:
{
"StringListNull": null,
"StringListEmpty": [],
"StringListPopulated": ["one", "two"]
}
Well, you can use Newtonsoft.Json or Json.NET for serializing or deserializing the Json. It will give you the required results.
This is the code I tried with it:
static void Convert()
{
string K = #"{ ""StringListNull"": null, ""StringListEmpty"": [], ""StringListPopulated"": [""one"", ""two""]}";
var list= JsonConvert.DeserializeObject<ImportObject>(K);
}
public class ImportObject
{
public List<string> StringListNull { get; set; }
public List<string> StringListEmpty { get; set; }
public List<string> StringListPopulated { get; set; }
}
And in the list object is exactly as you want.
I am attempting to write a code that finds objects in MongoDB collection with Linq.
Here's my code:
class Program
{
static void Main(string[] args)
{
var client = new MongoClient();
var db = client.GetDatabase("SoundsDB");
var collection = db.GetCollection<Sound>("SoundsCollection");
string myID = "0vvyXSoSHI";
var myObjects = collection
.Find(b => b.objectId == myID);
}
}
public class Sound
{
public string _id { get; set; }
public Result[] results { get; set; }
}
public class Result
{
public Audio_File audio_file { get; set; }
public DateTime createdAt { get; set; }
public string location { get; set; }
public string objectId { get; set; }
public DateTime updatedAt { get; set; }
}
public class Audio_File
{
public string __type { get; set; }
public string name { get; set; }
public string url { get; set; }
}
Here's the JSON in my MongoDB collection:
{
"_id" : ObjectId("56acced71b8ac8702446e8c6"),
"results" : [
{
"audio_file" : {
"__type" : "File",
"name" : "tfss-3c489351-0338-4903-8d94-a0f0c7091ef9-hi.m4a",
"url" : "http://files.parsetfss.com/hithere.m4a"
},
"createdAt" : "2014-12-27T22:59:04.349Z",
"location" : "Home",
"objectId" : "0vvyXSoSHI",
"updatedAt" : "2015-02-26T22:48:02.264Z"
}
]
}
I am trying to make it work but in the following line:
.Find(b => b.objectId == myID)
I get this error:
Cannot convert lambda expression to type 'MongoDB.Driver.FilterDefinition' because it is not a delegate type
Any idea how can I fix it and be able to search through the JSON for objects using their objectId?
Thanks!
I think the problem is that you are searching for a sub-document, not the main doc. Try this:
var myObjects = collection
.Find(b => b.results.Any(r=>r.objectId == myID));
Also - make sure that the objectId value is actually a string in your collection. It seems like it's a string in the object model but an objectId in the db. You may need to (a) change your object model and (b) change that query so that you are asking for r.objectId == ObjectId.Parse(myID) instead of the way I wrote it.
c# MongoDb .Find is Async
If you're using the c# drivers, you probably also need to implement async for this call:
static void Main() {
MainAsync().Wait();
}
static async Task MainAsync() {
var client = new MongoClient();
var db = client.GetDatabase("SoundsDB");
var collection = db.GetCollection<Sound>("SoundsCollection");
string myID = "0vvyXSoSHI";
var myObjects = await collection
.Find(b => b.objectId == myID).ToListAsync();
}
This way, you are using find, and converting the results to a list (so, myObjects will be a List<SoundsCollection> object).
I' m developing some WebAPI and have to return HttpResponseMessage with 2 standart service fields and one field which contains an array. Something like this:
{
field1:"test",
field2:123,
array:[{},{}]
}
But actually i need several responses which should differ only in name of array property:
{
field1:"test",
field2:123,
someArray:[{},{}]
}
and
{
field1:"test",
field2:123,
someOtherArray:[{},{}]
}
Type of elemnts in array is the same in each response. So I want to create one class for such type of responses and just change its PropertyName. Like this one:
public class Response
{
public int field2 { get; set; }
public string field1 { get; set; }
[JsonProperty(PropertyName = ???)]
public IEnumerable<SomeType> Array { get; set; }
}
How can I implement it?
You could also consider using a dictionary.
[HttpGet, Route("api/yourroute")]
public IHttpActionResult GetSomeData()
{
try
{
var data = new Dictionary<string, dynamic>();
data.Add("field1", "test");
data.Add("field2", 123);
var fieldName = someCondition == true? "someArray" : "someOtherArray";
data.Add(fieldName, yourArray);
return Ok(data);
}
catch
{
return InternalServerError();
}
}
My application is asp.net. I have to send some values back to server. For this I create a object serialize it and send it to server. At server I try to de-serialize it
Following is my code
[Serializable]
public class PassData
{
public PassData()
{
}
public List<testWh> SelectedId { get; set; }
public string SelectedControlClientId { get; set; }
public string GroupTypeId { get; set; }
public string SectionTypeId { get; set; }
}
[Serializable]
public class testWh
{
public testWh()
{
}
public string Id { get; set; }
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
//this can not serialize the SelectedId and the count remains 0
PassData data = serializer.Deserialize<PassData>(jsonString);
//this serialize in an anonymous object with key value pair
var data2 = serializer.DeserializeObject(textHiddenArguments.Text);
Following is my Json Serialized String
{
"SelectedId":{"0":"ABCD","1":"JKLM"},
"SelectedControlClientId":"YTUTOOO",
"GroupTypeId":3,
"SectionTypeId":"1"
}
quotes escaped string
"{\"SelectedId\":{\"0\":\"ABCD\",\"1\":\"JKLM\"},\"SelectedControlClientId\":\"YTUTOOO\",\"GroupTypeId\":3,\"SectionTypeId\":\"1\"}"
My Problem is Selected Id is array of testWH object. But when I try to desrialize it, the SelectedId property of PassData which is list does not get serialized and count remains zero.
I tried using array instead of List, which gave an exception "no parameter less constructor..."
Could any one explain the what I am doing wrong here ?
The key problem here is that the JSON doesn't match the objects you have constructed. You can see this by writing the data you want and serializing:
var obj = new PassData
{
SelectedId = new List<testWh>
{
new testWh { Id = "ABCD"},
new testWh { Id = "JKLM"}
},
GroupTypeId = "3",
SectionTypeId = "1",
SelectedControlClientId = "YTUTOOO"
};
string jsonString = serializer.Serialize(obj);
which gives JSON like:
{"SelectedId":[{"Id":"ABCD"},{"Id":"JKLM"}],
"SelectedControlClientId":"YTUTOOO","GroupTypeId":"3","SectionTypeId":"1"}
So now you need to decide which you want to change; the JSON or the classes. The following alternative class works fine with your original JSON, for example:
public class PassData
{
public Dictionary<string,string> SelectedId { get; set; }
public string SelectedControlClientId { get; set; }
public string GroupTypeId { get; set; }
public string SectionTypeId { get; set; }
}