I am working with a vendor who has a Restful API infrastructure that allows for "custom fields" on certain entities. When you create a custom field on one of their entities through their interface, you give the custom entity a name. However, in their API, you try to use that custom field, it is actually specified by an int (which represents a unique ID for that field). For example, the first custom field you create on an entity will have an ID of 1, and that is how you access or read that field from the API.
So in the below Json response sample, you'll see that the custom fields for enrollment are returned in the "enrollment fields" collection. 4 is the ID of the custom field, and ABC123 is the value populated in that custom field.
"enrollment_fields":{
"4":"ABC123"
},
I'm not quite sure how I would handle this in my Object Class. Obviously I can't give an object member a number as a name. How would I go about deserializing this type of member into my object so that I can read the value ABC123?
Since Object in C# can't have property as number, there is two way you can do
If your key is not going to change:
[JsonProperty(PropertyName = "4")]
public String Four { get; set; }
Else, you can use a Dictionary<string, string>.
Here I create a sample console app for your demonstration purpose.
class Program
{
static void Main(string[] args)
{
//This is your sample json that comes from Rest API
string json = #"
{'enrollment_fields':{
'4':'ABC123',
'5': 'XYZ123',
'6': 'PQR123'
}
}";
//Deserialize your json into Dictionary of dictionary.
var obj = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(json);
//Get your desired key from outer dictionary
var enrollment_fields = obj["enrollment_fields"];
//Loop on inner dictionary key to get values
foreach (string key in enrollment_fields.Keys)
//Here you get your dynamic key. e.g. 4,5,6
Console.WriteLine(key + ": " + enrollment_fields[key]);
Console.ReadLine();
}
}
Note: Download Newtonsoft.json form Nuget Package Manager and in your program use namespace like using Newtonsoft.Json;.
Output:
Related
How can I DeserializeObject the following JSON string to a C# object
{"":["Waybill already exist"]}
In some instances the "" can contain a value as well
Like
{"RecevierAddress1" : ["Receiver address 1 can not be blank]}
Whereas what You ask is not possible in principle, because an object property must have a name, what you can do is convert it to a .net JsonDocument which can have properties of zero length string naming.
I presume RL data cause for you to have to handle this, which of cause indicates poor data quality besides that, but You should be able to process it using this technique, here from a unit test
[Fact]
public void SerializeSillyObjectJsonTest()
{
string serialized = "{\"\":[\"Waybill already exist\"]}";
var jdoc = System.Text.Json.JsonDocument.Parse(serialized);
Assert.NotNull(jdoc);
var jsonElement = jdoc.RootElement.GetProperty("");
Assert.Equal(1, jsonElement.GetArrayLength());
}
So You see you can also check on if your property with said name exist and choose what to look for
jdoc.RootElement.TryGetProperty("RecevierAddress1", out var receiverAddressElement)
You can use JsonProperty("") to set the property name to an empty string
class root
{
[JsonProperty("")]
public string[] x;
}
JsonConvert.DeserializeObject<root>(#"{"""":[""Waybill already exist""]}")
For dynamic names, you can either have two properties, or deserialize to a dictionary
JsonConvert.DeserializeObject<Dictionary<string, string[]>>(#"{"""":[""Waybill already exist""]}")
Here is the response I am getting from Api which is dynamic as shown in the picture. I got the value in customfield_10011 key. In the other object down I am getting value in customfield_10014 key. Now how should I loop it and save data in c#?
I had a similar problem with Jira API.
If you are 100% sure that those custom properties will not change then for sure go the dynamic route.
I have been integrating with multiple Jira instances and they had different custom fields for the same property, so a more fluent mapping is preferred, because it can be done dynamically from some configuration.
This can be achieved with a CustomContractResolver of JsonConvert.
Example:
return JsonConvert.DeserializeObject<JiraIssuePayload>(str, new JsonSerializerSettings()
{
ContractResolver = new CustomContractResolver(new Dictionary<string, string>
{
{"EpicName", "customfield_10011" },
{"Epic", "customfield_10012" }, // these could come from some configuration object
});
}
What is done here is that you tell JsonConvert to deserialize customfield_10011 to the property EpicName of your type (and Epic for the other one).
Using Json.Net it is simple enough to serialize it to Dynamic.
dynamic myDynamicJson = JsonConvert.DeserializeObject("{ 'environment': null, 'customfield_10027': "Multi Sensor Updated" }");
string customfield10027 = myDynamicJson.customfield_10027;
Edit
To get the field name from config I would rather go for the custom resolver method. But in case you can't:
dynamic myDynamicJson = JsonConvert.DeserializeObject("{ 'environment': null, 'customfield_10027': 'Multi Sensor Updated' }");
string myFieldNameFromConfig = "customfield_100273";
string result = myDynamicJson[myFieldNameFromConfig];
I am trying to build a solution fitting with the problem of not knowing what kind of Setting type I am dealing with.
I got a Dictionary<string, Type> (which I initially wanted to make <string, class> but that didn't work)
that I want to fill with the setting code and the type of class attached to it i.e.
{ "person_customField", typeof(CustomFieldModel) }
Why I want to do this is because I have a field in my database filled with json data that should be deserialized to a List<> but I don't know what kind of setting it is until I get the object from the database. I can use the Code field to detemine what type it is (person_CustomField should use the CustomFieldModel class, but emailSetting should use EmailSettingModel to match parameters to.
Is there a way to successfully make this statement work with?
JsonConvert.DeserializeObject<List<SettingTypes[record.SettingCode]>>(record.SettingValues).ToList<ISetting>()
Or should I go a different route
Code Sample:
public static readonly Dictionary<string, Type> SettingTypes = new Dictionary<string, Type>()
{
{ "person_CustomFields", typeof(CustomFieldModel)},
};
public static TenantSettingEdit ConvertToTenantSettingEdit(this T_TenantSetting rec)
{
var test = SettingTypes[rec.TENS_Code];
TenantSettingEdit item = new TenantSettingEdit()
{
IDToken = rec.TENS_TenantSettingID.toVirtualGuid().ToString(),
Code = rec.TENS_Code,
Settings = JsonConvert.DeserializeObject<List<SettingTypes[rec.TENS_Code]>>(rec.TENS_Setting).ToList<ITenantSetting>(),
IsActive = rec.TENS_ActiveRec,
};
return item;
}
(I have done this before with PHP but I am not sure if this is even remotely possible with C#)
Why I want to do this is because I have a field in my database filled
with json data that should be deserialized to a List<> but I don't
know what kind of setting it is until I get the object from the
database.
If you're using Json.Net for JSON serialization/deserialization you can use the TypeNameHandling property to embed Type information in the resulting JSON. That JSON can the be deserialized by Json.Net without additional information. If it is necessary to map custom values to the types instead of the automatically generated ones you can use a SerializationBinder (check out this answer).
If none of those help you, you can still fall back to reflection in the way M Kloster describes.
You cannot use a variable as the type parameter in the code, no. What you need to do is to generate the type-specific method by reflection:
var genericMethod = ((Func<string, int>)Json.DeserializeObject<int>).Method.GetGenericMethodDefinition();
var boundMethod = genericMethod.MakeGenericMethod(SettingTypes[record.SettingCode]);
var result = boundMethod.Invoke(null, rec.TENS_Setting)...
I'm using ASP.NET MVC 4 with the Parse database (https://www.parse.com/). I have a table called app and a field called reviews. In this field i want to save a json object with the following format:
[{"Title":"a title", "url":"a url"}, {"Title":"another title", "url":"another url"}, etc...]
As I have read in the documentation (https://www.parse.com/docs/dotnet_guide#objects-types) Parse supports objects that implement IDictionary<string, T> and IList<T> so i have the following code:
var requestFormInformation = new ParseObject("app");
requestFormInformation["Reviews"] = requestForm.Reviews.ToList();
Reviews property is an IEnumerable<Review> and this is the Review class
public class Review
{
public string Title { get; set; }
public string Url { get; set; }
}
There is no error thrown when i save this code and save in the database but the item is not saved.
You might want to place your code into a try-catch (ParseException) to see if the save fails for some reason.
Sidenote: the Parse help page suggests that you start the class name with a uppercase character and the key name with a lowercase character. "app" should be "App" and "Reviews" should be "reviews".
Another thing could be authentication or authorization. Are you properly authenticated and do you have the rights to save this object.
You need to be clear about how you want to save the data. You say you want to save it as JSON, which is a string serialization format, so the column should be of type string, and you'll have to handle JSON serialize/deserialize yourself. I don't think this is what you actually want, so forget about JSON as that is an implementation detail inside Parse.
If instead you want it to just serialize your collection you don't have to do anything special. As per the documentation on object types you can store anything that implements IList or IDictionary including nested objects.
I would suggest you try an experiment with a simple class that has a List as one of its properties:
var foo = new ParseObject("Foo");
var reviews = new List<Review>();
reviews.Add(new Review { Title = "Review 1" });
reviews.Add(new Review { Title = "Review 2" });
foo["reviews"] = reviews;
await foo.SaveAsync();
Once that is working, test incremental changes till you find out where things have gone wrong.
I am developing a windows 8 app, and i have some javascript that stores a serialized object into roaming settings, i.e:
var object = [{"id":1}, {"id":2}]
roamingSettings.values["example"] = JSON.stringify(object);
I also i have a c# part to the application (for running a background task), that needs to read that JSON, and turn it into an object so i can iterate over it. And this is where i am having some issues, i am using JSON.NET to do the work, but every thing i turn turns up with an error:
// this looks like "[{\"id\":1},{\"id\":2}]"
string exampleJSON = roaming.Values["example"].ToString();
// dont know if this is correct:
List<string> example = JsonConvert.DeserializeObject<List<string>>(exampleJSON );
That give an error of:
Error reading string. Unexpected token: StartObject. Path '[0]', line 1, position 2.
So i am at a loss of what to do, i have been working on it for last few hours, and i am quite unfamiliar with c#, so resorting to the help of stackoverflow ;D
Thanks in advance for any help :)
Andy
Json.Net has a nice method DeserializeAnonymousType. No need to declare a temporary class.
string json = "[{\"id\":1},{\"id\":2}]";
var anonymous = new []{new{id=0}};
anonymous = JsonConvert.DeserializeAnonymousType(json,anonymous);
foreach (var item in anonymous)
{
Console.WriteLine(item.id);
}
You can even use the dynamic keyword
dynamic dynObj = JsonConvert.DeserializeObject(json);
foreach (var item in dynObj)
{
Console.WriteLine(item.id);
}
You are trying to parse your JSON array into a List of strings, which doesn't work. The JSON object you provide is actually a list of objects containing an integer property called 'id'.
Perhaps try creating a class (say, MyClass) with just that property, and deserialize into List.
Your json containts a collection of objects with an id property, something like this:
class IdObject {
public int id { get; set; }
}
You could then do:
JsonConvert.DeserializeObject<List<IdObject>>(exampleJSON);
Because the IdObject class has a property id to match your json serialized value, it will be mapped back.