Server not receiving lists inside of JSON object passed in - c#

These are the data contracts that are being used in the function.
public class ResumeSkillsListDataContract : IResumeSkillsListDataContract
{
public IList<ISkillDataContract> KnownSkillsList { get; set; }
public IList<ISkillDataContract> BadSkillsList { get; set; }
public IList<ISkillDataContract> NewSkillsList { get; set; }
public Int32 PersonId { get; set; }
}
public class SkillDataContract : ISkillDataContract
{
public String Name { get; set; }
public Nullable<Int32> Id { get; set; }
public Nullable<Boolean> IsAssigned { get; set; }
public Nullable<Int32> SkillCategoryId { get; set; }
public Nullable<Int32> SkillCategoryMappingId { get; set; }
}
This is the function in the controller. I am expecting three populated lists and a PersonId to be passed in. However, I am only receiving the PersonId. In my Post, I see the data I am expecting to see in the console but when debugging the controller, item.List is empty every time.
public IList<ISkillDataContract> PostResumePersonSkills(ResumeSkillsListDataContract item)
{
var newList = item.KnownSkillsList;
var ignoreList = item.BadSkillsList;
var existingList = item.NewSkillsList;
var personId = item.PersonId;
return resumePersonSkillsBusinessLibrary.PostSkills(newList, ignoreList, existingList, personId);
}
Here is a quick snapshot of what im sending to the server. Any idea what could be wrong? Thanks.
$scope.doneWithSkills = function () {
var resumeCollection = {
KnownSkillsList: $scope.KnownSkillsList, BadSkillsList: $scope.IgnoredSkillsList,
NewSkillsList: $scope.SaveAsSkillsList, PersonId:$scope.ParsedPerson.Person.PersonId
};
resumeParserService.PostResumeSkills(resumeCollection);
};
Function in the resumeParserService
self.PostResumeSkills = function (skills) {
var url = 'ResumeSkill/PostResumePersonSkills';
console.log(skills);
webApiService.Post(url, skills);
};
Sample JSON being passed.
{"KnownSkillsList":[{"Name":"C++","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":154},{"Name":"Unix","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":219},{"Name":".Net","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":139},{"Name":"Clearcase","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":155},{"Name":"Uml","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":218},{"Name":"Xml","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":239},{"Name":"Java","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":173},{"Name":"Python","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":199},{"Name":"Visual Basic","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":223}],"BadSkillsList":[],"NewSkillsList":[{"Name":"Algorithms","Id":null,"IsAssigned":null,"SkillCategoryId":3,"SkillCategoryMappingId":null}],"PersonId":1203}

I would expect this is caused by your lists ResumeSkillsListDataContract being lists of an interface. The problem is going to be that when the JSON is deserialized the deserializer does not know what concrete type to instantiate.
Try changing to this and see if it resolves the problem
public class ResumeSkillsListDataContract : IResumeSkillsListDataContract
{
public IList<SkillDataContract> KnownSkillsList { get; set; }
public IList<SkillDataContract> BadSkillsList { get; set; }
public IList<SkillDataContract> NewSkillsList { get; set; }
public Int32 PersonId { get; set; }
}

Related

Store Object with Dynamic property in Cosmos DB

I have a message processor where I would like to take a lump of json with a wrapper of known schema, but with a property that is a dynamic object like the following:
public class NotificationDetails
{
[JsonProperty(PropertyName = "id")]
public string NotificationID { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateSent { get; set; }
public string TemplateUrl { get; set; }
public dynamic Model { get; set; }
}
as you can see, the last property is of dynamic. the notifications will all have different Model schemas, so I would like it to just be stored as a nested object.
That said, when I attempt to Create the object via
client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, collectionId), item)
I get the following error message:
The best overloaded method match for 'MyClass.CreateNotification(NotificationDetails))' has some invalid arguments
I thought I could throw anything into these docs. what am I doing wrong? should I use something other than dynamic for this Model property?
UPDATE I figured out it was something about how I was calling the Wait() method on the task returned from the DocumentClient. Once I reverted to the async await strategy it started working correctly.
According to your description. I have tested your code and it worked as below. You can refer to what I did:
public static void CreateCosmosDocument()
{
DocumentClient client = new DocumentClient(new Uri("https://xxxxx/"), "C2y6yDjf5/R+ob0N8A7Cgv30VRDJxxxxM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", new ConnectionPolicy { EnableEndpointDiscovery = false });
TestEntity testEntity = new TestEntity { x = 11, y = 11, name = "wakaka", dynam = "hello dynam" };
var createdItem = client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri("ToDoList", "Items"), new NotificationDetails { DateCreated=DateTime.Now, DateSent=DateTime.Now, TemplateUrl="www.baidu.com", Model= testEntity });
}
Class of NotificationDetails:
public class NotificationDetails
{
[JsonProperty(PropertyName = "id")]
public string NotificationID { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateSent { get; set; }
public string TemplateUrl { get; set; }
public dynamic Model { get; set; }
}
Class of TestEntity which act as a nested object:
class TestEntity
{
public ObjectId _id { get; set; }
public string name { get; set; }
public double x { get; set; }
public double y { get; set; }
public double z { get; set; }
public dynamic dynam { get; set; }
}
Screenshot of result:
If the error still occured, you'd better share your more detailed code with us for further research.

Can't deserialize an indexed name value pair child node C#

I'm running into an issue when I am trying to deserialize a webAPI GET call that returns a JSON object. The issue being one particular property is always null after being deserialized.
The JSON object looks like this:
{
"status":"OK",
"masterlist":{
"session":{
"session_id":intValue,
"session_name":"stringValue"
},
"0":{
"bill_id":intValue,
"number":"stringValue",
"change_hash":"stringValue",
"url":"stringValue",
"status_date":"dateValue",
"status":"stringValue",
"last_action_date":"dateValue",
"last_action":"stringValue",
"title":"stringValue",
"description":"stringValue"
},
"1":{
"bill_id":intValue,
"number":"stringValue",
"change_hash":"stringValue",
"url":"stringValue",
"status_date":"dateValue",
"status":"stringValue",
"last_action_date":"dateValue",
"last_action":"stringValue",
"title":"stringValue",
"description":"stringValue"
},
"2":{
"bill_id":intValue,
"number":"stringValue",
"change_hash":"stringValue",
"url":"stringValue",
"status_date":"dateValue",
"status":"stringValue",
"last_action_date":"dateValue",
"last_action":"stringValue",
"title":"stringValue",
"description":"stringValue"
}
}
}
As you can see the second property of masterlist isn't an array, that would make life too easy... But it looks more like a collection of name/value pairs. I have reviewed This post and the associated one listed within but they both pertain to if the name/value pair where at the root level where mine is not.
My method that I am using to deserialize is:
BillMaster billMasterList = new BillMaster();
using (HttpClient client = new HttpClient())
{
string json = Get("&op=getMasterList&state=TN");
billMasterList = JsonConvert.DeserializeObject<BillMaster>(json);
}
And the model classes the deserializer is binding to:
public class BillMaster
{
public string Status { get; set; }
public BillMasterList masterlist { get; set; }
}
public class BillMasterList
{
public BillMasterList_Session session { get; set; }
public Dictionary<int, BillMasterList_Array> BillMasterList_Array { get; set; }
}
public class BillMasterList_Array
{
public int bill_id { get; set; }
public string number { get; set; }
public string change_hash { get; set; }
public string url { get; set; }
public string status_date { get; set; }
public string status { get; set; }
public string last_action_date { get; set; }
public string last_action { get; set; }
public string title { get; set; }
public string description { get; set; }
}
When I run the code I don't throw any errors and I have values in my object except for BillMasterList_Array, that is always null. I'm obviously not doing something right but what it is alludes me.

AutoMapper returns NULL when returning a list

Code without AutoMapper:
List<CountryDM> countryDMList = _countryRepo.GetCountry();
List<CountryVM> countryVMList = new List<CountryVM>();
foreach (CountryDM countryDM in countryDMList)
{
countryVMList.Add(CountryVM.ToViewModel(countryDM));
}
return countryVMList;
I used AutoMapper for the above task. But it returns a NULL list. Please refer the below code:
List<CountryDM> countryDMList = _countryRepo.GetCountry();
Mapper.CreateMap<List<CountryDM>, List<CountryVM>>();
List<CountryVM> countryVMList = new List<CountryVM>();
return Mapper.Map<List<CountryVM>>(countryDMList);
public class CountryDM
{
public int ID { get; set; }
public string CountryCode { get; set; }
public string Description { get; set; }
}
public class CountryVM
{
public int ID { get; set; }
public string CountryCode { get; set; }
public string Description { get; set; }
}
You don't need to define a mapping between lists, just between objects, AutoMapper will know how to extrapolate that:
Mapper.CreateMap<CountryDM, CountryVM>();
the rest stays the same

Updating List<T> in DbContext

I have a Model like this
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<string> SolvedBy { get; set; }
}
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
}
and then Controller like this. But I cannot update the List "SolvedBy", the next time I step through with the debugger, the list is still empty.
[HttpPost]
public string Index(string flag = "", int id=0)
{
Challenge challenge = db.Challenges.Find(id);
if (flag == challenge.Flag)
{
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<string>();
}
chall.SolvedBy.Add(User.Identity.Name);
db.Entry(chall).State = EntityState.Modified;
db.SaveChanges();
//congrats, you solved the puzzle
return "got it";
}
else
{
return "fail";
}
}
is there any way around it to make a list of strings kept in the database?
EF don't know how to store an array in database table so it just ignore it. You can create another table/entity or use XML/JSON to store the list. You can serialize the list before saving and deserialize it after loading from database
A List<T> in a model would normally map to a second table, but in your DbContext you only have a single table. Try adding a second table.
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
public DbSet<Solution> Solutions {get; set;}
}
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<Solution> SolvedBy { get; set; }
}
public class Solution
{
public int ID { get; set; }
public string Name { get; set; }
}
Then your controller can use code along the lines of...
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<Solution>();
}
chall.SolvedBy.Add(new Solution {Name=User.Identity.Name});
None of the above has been tested and I may have made some mistakes there, but the general principle I want to illustrate is the fact that you need another table. The List<T> represents a JOIN in SQL.

Why can't I send my custom class through my webservice?

I have these classes:
public abstract class CustomField
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public FieldType Type { get; set; }
public enum FieldType
{
String = 0,
Integer = 1,
Boolean = 2,
List = 3
}
}
public class StringCustomField:CustomField
{
public String Value { get; set; }
public Int32 MinLenght { get; set; }
public Int32 MaxLenght { get; set; }
public StringCustomField()
{
this.Type = FieldType.String;
}
}
public class CustomGroup
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public List<CustomField> FieldList = new List<CustomField>();
}
When I try to transfer CustomGroup through my webservice I get this error:
The remote server returned an error: NotFound
Serialization is failing when C# tries to transfer my StringField through my CustomField.
What am I doing wrong?
Marc Gravel tell me to do that and i understand the solution but some thing is wrong, no effects, cath the same error!! , help!!
[XmlInclude(typeof(StringCustomField))]
[XmlInclude(typeof(IntegerCustomField))]
[XmlInclude(typeof(BooleanCustomField))]
[XmlInclude(typeof(ListCustomField))]
public abstract class CustomField
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public FieldType Type { get; set; }
public enum FieldType
{
String = 0,
Integer = 1,
Boolean = 2,
List = 3
}
}
If you are sending subclasses as xml, you will need [XmlInclude]:
[XmlInclude(typeof(StringCustomField))]
public abstract class CustomField
{...}
You can add multiple [XmlInclude(...)] markers for any other subclasses in the model.
List<CustomField> will serialize and deserialize to a CustomField[] if you're using a web service, won't it?
use
public class CustomGroup
{
public String Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public List<CustomField> FieldList = new List< StringCustomField >();
}
instead
If i understand you correctly, you should
1. connect your web service to your app
2. use the namespace of the WS, so all the classes will be used from the Proxy
i don't think that the local class will be understood by the remote web serivce correctly, even if you're using the same assembly on both parties

Categories

Resources