Deserialize Json for CRM Entities - c#

I have the following Json defining a specific configuration which has to be stored in custom CRM entities:
{
"useraccountid": "U12345",
"profiles": [
{
"applicationrole": "RelationshipManager",
"maindatascopetypecd": 858000001,
"organisationalunitno": "10000000",
"ishierachical": 1
},
{
"applicationrole": "CountrySpecialist",
"maindatascopetypecd": 858000002,
"attributetypecd": 858000000,
"attributevalue": "SY",
"isreadonly": 0
}
]
}
Each user can have multiple user provisioning profiles. this data finally needs to be written into custom CRM entities. The "useraccountid" is a lookup to a systemuser (entityreference).
What I already have is e deserializer like this:
public static T JsonDeserialize<T>(string jsonString)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
T obj = (T)ser.ReadObject(ms);
return obj;
}
And classes like this for the parent class:
[DataContract]
class CrmUserProvisioning
{
[DataMember]
public String clm_useraccountid
{
get; set;
}
// will be set on runtime
public DateTime clm_createdon
{
get; set;
}
[DataMember]
public List<CrmProfile> clm_profiles { get; set; } = new List<CrmProfile>();
}
and for the profile(s)
[DataContract]
public class CrmProfile
{
[DataMember]
public Guid clm_userprovisioningid
{
get; set;
}
[DataMember]
public string clm_applicationrole
{
get; set;
}
[DataMember]
public int clm_maindatascopetypecd
{
get; set;
}
[DataMember]
public string clm_organisationalunitno
{
get; set;
}
[DataMember]
public bool clm_ishierachical
{
get; set;
}
[DataMember]
public int clm_applyingtypecd
{
get; set;
}
[DataMember]
public int clm_globalopenaccesscd
{
get; set;
}
[DataMember]
public int clm_attributetypecd
{
get; set;
}
[DataMember]
public string clm_attributevalue
{
get; set;
}
[DataMember]
public bool clm_isreadonly
{
get; set;
}
}
missing fields in the config for the profile will not be deserialized. I'm stuck with the fact on how deserialize this config regarding the fact that the config can contain many profile classes but only one parent class (UserProvisioning).
Could anybody put me in the right direction? Any help is really appreciated.
kind regards
UPDATE 02.03.2018
After having deserialized the Jsion into object(s) I need to store now the objects into the corresponding Microsoft Dynamics CRM entites. The entities and the attributes are named like the object- and the property-names.
I already have the organisation service, etc. I only need to know how to map the objects to a regular crm create or update request.
If somebody could help me out with this, it would be very appreciated.

Use DataContract and DataMember
[DataContract]
class UserProvisioning
{
[DataMember]
public String useraccountid
{
get { return this.useraccountid; }
set { this.useraccountid = value; }
}
// Will be set on runtime
public DateTime createdon
{
get { return this.createdon; }
set { this.createdon = value; }
}
// Must declare this for the child list of Profile
[DataMember]
public List<Profile> profiles {get;set;}=new List<Profile>();
}
In CrmProfile also set DataContract for the class and DataMember for the properties.
Check the docs:
DataContract
DataMember. Only the properties with DataMember will serialize.
You can also set required properties or set not to serialize default values.

Related

Consume Data From this endpoint

I am getting tdata from a certain endpoint and the problem id on serialization to my classes. I want to cast the bellow data to my class but cant get how the class should be structured. Check out the data .....
{
"-LYG_AI_oGYjNBrzMlKF": {
"chatDispayText": "",
"chatId": "-LYG_AI_oGYjNBrzMlKF",
"chatName": "",
"chattype": "single",
"imageUrl": "https://wallpaper.wiki/wp-content/uploads/2017/04/wallpaper.wiki-Amazing-celebrities-hd-wallpaper-PIC-WPD004734.jpg",
"lastMessageSent": "aiye",
"lastMessageSentTime": 1549704416263,
"synched": false,
"users": {
"-LYG_AIZ5MvTbjR7DACe": "Uicpm3L15TX0c15pKCI6KUEARyB3",
"-LYG_AI_oGYjNBrzMlKE": "Xsr0z9lsqNOEytX61lJvaGz1A8F2"
}
}
}
If the data you get out the endpoint has a dynamic structure, you can make use of a key-vale pair collection or a dictionary. For instance:
JObject jObject = JObject.Parse(Data); // This would already give you a key-value pair collection
Dictionary<String,Object> collection = new Dictionary<String, Object>();
foreach(var obj in jObject){
collection.Add(obj.Key, obj.Value);
}
However, this isn't a strongly typed approach which means that it is not effective in the majority of scenarios. A better solution when dealing with endpoints would be to define a class with fixed schema, actually something you need in your code, and then map the class to the object yielded by the endpoint using a metadata struct. For example:
public class ChatInfoModel
{
[JsonProperty(Metadata.ChatId)]
public long ChatId { get; set; }
[JsonProperty(Metadata.ChatId, Required = Required.AllowNull)]
public String Message { get; set; }
}
public struct Metadata
{
public const String ChatId = "userChatId";
public const String Message = "messageTxt";
}
And then
var deserializedObject = JsonConvert.DeserializeObject<ChatInfoModel>(data);
However, if your class has the exact same naming convention (but should not necessarily follow the camelCase naming convention) for its properties as in the serialized data, the JsonProperty attribute would not be needed.
You can also deserialize the object without using JsonProperty attribute manually using the first approach, and it is actually advantageous in certain scenarios where your schema comes from a configuration file rather than a struct.
Take inspiration from the Structure below:
public class Rootobject
{
public LYG_AI_Ogyjnbrzmlkf LYG_AI_oGYjNBrzMlKF { get; set; }
}
public class LYG_AI_Ogyjnbrzmlkf
{
public string chatDispayText { get; set; }
public string chatId { get; set; }
public string chatName { get; set; }
public string chattype { get; set; }
public string imageUrl { get; set; }
public string lastMessageSent { get; set; }
public long lastMessageSentTime { get; set; }
public bool synched { get; set; }
public Users users { get; set; }
}
public class Users
{
public string LYG_AIZ5MvTbjR7DACe { get; set; }
public string LYG_AI_oGYjNBrzMlKE { get; set; }
}

How to ignore ObjectSchema and Ream properties when serializing a realmObject

I m trying to serialize a RealmObject in my uwp project and I would like to know if there is any way to to ignore ObjectSchema and Ream properties when serializing a realmObject ? I tried to create a constuctor to avoid copying these two properties but It doesn't worked for me.
This is my object :
public class Sector : RealmObject, NodeBase
{
[PrimaryKey]
public int id { get; set; }
public string key { get; set; }
[Ignored]
public Dictionary<string, string> title { get; set; }
[JsonIgnore]
public Dictionary Title { get; set; }
public int position { get; set; }
public bool template_is_carousel { get; set; }
public bool isVisible { get; set; }
public IList<string> filter { get; }
[Ignored]
public DisplayType display_type { get; set; }
[JsonIgnore]
public string DisplayType { get; set; }
public int parent_id { get; set; }
public string parent_type { get; set; }
public string image_url { get; set; }
public string banner_color { get; set; }
public int template_rows { get; set; } = 3;
public int template_columns { get; set; } = 2;
public Sector(Sector sector)
{
this.id = sector.id;
this.key = sector.key;
this.Title = sector.Title;
this.title = sector.title;
this.position = sector.position;
this.template_is_carousel = sector.template_is_carousel;
this.isVisible = sector.isVisible;
this.filter = sector.filter;
this.display_type = sector.display_type;
this.DisplayType = sector.DisplayType;
this.parent_id = sector.parent_id;
this.parent_type = sector.parent_type;
this.image_url = sector.image_url;
this.banner_color = sector.banner_color;
this.template_rows = sector.template_rows;
this.template_columns = sector.template_columns;
}
public Sector()
{
}
}
And this is how I m serializing my object :
private string serializeParameter(object parameter)
{
return JsonConvert.SerializeObject(parameter);
}
Serialization in Json.NET will serialize base class properties by default. The Sector class inherit from RealmObject class, then when serializing Sector object, all the base properties in the parent class RealmObject will be serialized.
To resolve this, you could try to use [JsonObject(MemberSerialization.OptIn)] attribute, in that case, properties without specify [JsonProperty] will not be serialized. For example, the following code will only serialize parent_type property,
[JsonObject(MemberSerialization.OptIn)]
public class Sector : RealmObject
{
[JsonProperty]
public string parent_type { get; set; }
}
Actually the simply way is to add [JsonIgnore] attribute for the properties in the parent class. But it looks like you are using a third package that you could not change the parent class RealmObject.
More details please reference
this thread.
To use which way is based on your requirements, you could also try to serialize it by Json relative APIs in UWP app without using the Json.Net. For example:
var jsonstring= Stringify();
public string Stringify()
{
JsonObject jsonObject = new JsonObject();
jsonObject["parent_type "] = JsonValue.CreateStringValue("test");
return jsonObject.Stringify();
}

Dynamic/Expando and JSON

There's a lot of Qs on this, but I need a solution without JSON.Net, etc. - I must use the canned stuff in Asp.Net MVC.
How can I serialize a POCO with a dynamic property - and get all the static properties, too? What I found was the dynamic only, or the static type which is easy.
e.g.
public class ReturnThisClassAsJSON {
public int Id {get; set; }
public string Name { get; set; }
public ContainedClass ContainedContents { get; set; }
}
public class ContainedClass {
public int Order { get; set; }
public string Label { get; set; }
public dynamic DynamicInfo { get; set; }
public List<dynamic> DynamicList { get; set }
}
My own answer:
I replaced the dynamic from the DynamicInfo and DynamicList from the ContainedClass with static types.
With the dynamic, I had 1 of 2 choices. Either serialize the dynamic to a string in its own serialization call using above SO question 5156664. (Which left me with the rest of the class I also wanted serialized and merged with it, thus this question). Or, incur this error:
"A circular reference was detected while serializing an object of type 'System.Reflection .RuntimeModule' ".
when attempting a single serialization call on the ContainedClass.
So, I transferred the dynamics into static-typed classes:
public class ColumnValue
{
public string Name { get; set; }
public string Value { get; set; }
}
public class DynamicRow
{
public List<ColumnValue> ColumnValue { get; set; }
}
and, change ContainedClass to this:
public class ContainedClass
{
public List<ColumnValue> DynamicInfo { get; set; }
public List<DynamicRow> Data { get; set; }
}
And, it serializes using out-of-the-box Asp.Net MVC:
return Json(ReturnThisClassAsJSON, JsonRequestBehaviour.AllowGet);

Converting infinitely nested objects in .NET Core

EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?

Why am I getting the exception "Consider using a DataContractResolver or add any types not known statically to the list of known types"

I'm trying to serialise a object to Xml using the DataContractSerializer. I have the following classes;
[ActiveRecord(Lazy = true)]
[KnownType(typeof(RoomType))]
[DataContract]
public class Room : ActiveRecordBase<Room>
{
[PrimaryKey]
[DataMember]
public virtual Int64 RoomId { get; protected set; }
[BelongsTo("RoomTypeId")]
[DataMember]
public virtual RoomType RoomType { get; set; }
[Property]
[DataMember]
public virtual Int64 HotelId { get; set; }
[Property]
[DataMember]
public virtual string Name { get; set; }
[Property]
[DataMember]
public virtual string Description { get; set; }
public static Room[] FindByHotelId(Int64 HotelId)
{
return (Room[])FindAllByProperty(typeof(Room), "HotelId", HotelId);
}
}
The RoomType class is
[ActiveRecord(Lazy = true)]
[DataContract]
public class RoomType : ActiveRecordBase<RoomType>
{
[PrimaryKey]
[DataMember]
public virtual int RoomTypeId { get; protected set; }
[Property]
[DataMember]
public virtual string Name { get; set; }
}
I use the following method to serialise the object
internal static XElement ObjectToXElement<T>(T source)
{
XDocument oXDocument = new XDocument();
try
{
using (var writer = oXDocument.CreateWriter())
{
// write xml into the writer
var serializer = new DataContractSerializer(source.GetType());
serializer.WriteObject(writer, source);
}
}
catch(Exception e)
{
using (var writer = oXDocument.CreateWriter())
{
// write xml into the writer
var serializer = new DataContractSerializer(oError.GetType());
serializer.WriteObject(writer, oError);
}
}
return oXDocument.Root;
}
The actual object I'm serialising is;
[KnownType(typeof(List<Room>))]
[KnownType(typeof(RoomType))]
[DataContract]
public class RoomTypeResponse
{
[DataMember]
public int Code { get; set; }
[DataMember]
public string Message { get; set; }
[DataMember]
public List<Room> Rooms { get; set; }
public RoomTypeResponse()
{
this.Rooms = new List<Room>();
}
}
But for some reason when I call the method to serialise the object I get the following exception;
Type 'Castle.Proxies.RoomTypeProxy' with data contract name
'RoomTypeProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies'
is not expected. Consider using a DataContractResolver or add any
types not known statically to the list of known types - for example,
by using the KnownTypeAttribute attribute or by adding them to the
list of known types passed to DataContractSerializer.
If I comment out the property in Room class, it works fine
[BelongsTo("RoomTypeId")]
[DataMember]
public virtual RoomType RoomType { get; set; }
I'm not sure why I am getting the exception, because I've added the knowtype attribute for RoomType ? What am I missing, that is causing this problem.
The problem is that one type (Castle.Proxies.RoomTypeProxy) is generated at runtime, so .NET knows nothing about it. This is not an NHibernate-specific problem. If you disable lazy loading and proxy generation, the problem will go away, but I understand it might be difficult.
Other option would be to use another serializer, like BinaryFormatter, but I don't know if that will work for you.

Categories