Mapping JSON (jQuery) to KeyValuePair - c#

I have a JSON object with numerous properties that I am submitting to a C# web service via jQuery.ajax() - it looks something like this:
var obj = {};
obj.LanguageCode = 1031;
obj.Gender = { 'Geschlecht': 'Mann' };
obj.City = { 'Stadt': 'Berlin' };
...
Some properties, like Gender and City, store a localized/translated prompt and response that I want to map to a KeyValuePair. I've tried formatting the Javascript in different ways, but the data only comes through when the datatype is Dictionary - when the datatype is KeyValuePair it doesn't work. For example:
private Dictionary Gender { get; set; } // works: Gender[0] == {[Geschlecht,Mann]}
private KeyValuePair City { get; set; } // doesn't work: City == {[,]}
I can use Dictionary if necessary since it works, but it seems like KeyValuePair is more appropriate and cleaner to use. Can you map Javascript objects to KeyValuePairs, or am I stuck with using Dictionary?

Looks like you need a collection of KeyValuePair objects, not a single one (even though your collection would only have one item) - that's all a Dictionary is, a collection with a few helpers around it.
But personally, I'd recommend building an actual class to represent your values, to organize it a little better - a little more verbose, but I think it's worth it.
// C#
public class LocalAndTranslated {
public string Localized { get;set; }
public string Translated { get;set; }
}
// JS
obj.Gender = { Localized: "Geschlecht", Translated: "Man" };
If you wanted to, you can even go so far as to define a "class" in javascript:
var LocalAndTranslated = (function() {
function LocalAndTranslated(localized, translated) {
this.Localized = localized;
this.Translated = translated;
}
return LocalAndTranslated;
})();
obj.Gender = new LocalAndTranslated("Geschlecht", "Man");

Related

Create a JSON object using properties of a C# class

I'm trying to construct a request body for a REST api call, and I need to create a JSON object with the list of properties I want to get back.
For eg: I have this C# object that I want to get back:
public class SomeProperties
{
public string TicketNumber { get; set; }
public Driver Driver { get; set; }
}
public class Driver
{
public string Name { get; set; }
}
To get this back, I need to put these properties in a JSON request body like this:
"properties": [
"ticketNumber",
"driver.name"
]
My attempt looks like this:
private string FetchProperties()
{
var fetchProperties = new
{
properties = new List<string>
{
"ticketNumber",
"driver.name"
}
};
var jsonResult = JsonConvert.SerializeObject(fetchProperties, Formatting.None);
return jsonResult;
}
But I don't want to hard code the properties like that.
So is there any way I can use property names from the object I want, to put in the list of strings that I made in the method above?
Thank You!
If I understand correctly,you need Metadata of model.
if you use EntityFramework, you can get metadata of your model
from this Code
and call BuildJsonMetadata() function
and if you use other mapper, I dont see any exist tool for generate metadata of model and you must generate it handly
somthing like this
First of, if you serialize the class you have (SomeProperties), you will not get driver.name. Instead you will get a string like this one that shows driver as an object,
{
properties : {
"ticketNumber" : "stringvalue",
"driver" : {
"name" : "stringValue"
}
}
}
That said, if you are interested in getting a json like this,
"properties": [
"ticketNumber",
"driver.name"
]
you will need a class (very simple one at that) that contains only a list of strings. properties is not an array of objects, but simply strings. From the looks of the FetchProperties method, you are creating an object with fetchProperties as the RootObject. Try something like this,
public class MyClass
{
[JsonProperty("fetchProperties")]
public Fetch FetchProperties { get; set; }
}
public class Fetch
{
[JsonProperty("properties")]
public List<string> Properties { get; set; }
}
private string FetchProperties()
{
MyClass obj = new MyClass()
{
FetchProperties = new Fetch()
{
Properties = new List<string>() { "ticketNumber", "driver.Name" }
}
};
return JsonConvert.SerializeObject(obj); // Formatting.None is by default
}
Now its your choice to hard code these values or, pass them as arguments or use a local variable that contains a list of all the strings you intend to store as "properties". You cant use enums because of violation in naming convention (driver.name) so these options should suffice.

Finding Root Url and Subsites Url In Collection

I have a strong typed list string collection consistenting of root level sites sometimes represented at the domain level, however sometimes not. For example:
http://x.com
http://x.com/y
http://x.com/y/w
http://x.com/y/z
http://a.com/b/c
http://a.com/b/c/d
http://a.com/b/c/e
I need to convert the string collection to a collection of strongly typed custom objects, such as the below:
public class UrlObject
{
public string url { get; set; }
public List<UrlObject> subUrls { get; set; }
}
The amount of characters and slashes in the "Parent" url can vary, I am curious if there is a way that building a collection that allows flexible for the size of the "Parent".
The expected output of this method would be a list collection with two objects, represented below:
object 1
Parent - http://x.com
subUrls- http://x.com/y,
http://x.com/y/w,
http://x.com/y/z
object 2
Parent: http://a.com/b/c
subUrls-http://a.com/b/c/d,
http://a.com/b/c/e
There is a class that already exists in .NET that will make your life a lot easier: System.Uri. Instead of your custom class, you can create a "conatiner" class like this:
public class UriContainer
{
public Uri Parent { get; set; }
public List<Uri> Children { get; set; }
}
You can easily turn a collection of string urls into Uri objects with a little bit of LINQ:
var urlStringList = new List<string>()
{
"http://x.com",
"http://x.com/y",
"http://x.com/y/w",
"http://x.com/y/z",
"http://a.com/b/c",
"http://a.com/b/c/d",
"http://a.com/b/c/e"
};
IEnumerable<Uri> uris = urlStringList.Select(x => new Uri(x));
From there you can GroupBy() the Host property, then inside each group, OrderBy() the Segments.Length property. Then take the First() one (this is the one with the least segments aka the "parent" per your example), then you take the rest of them as the "children":
var containerList = new List<UriContainer>();
foreach(var groupedUri in uris.GroupBy(x => x.Host))
{
var sorted = groupedUri.OrderBy(x => x.Segments.Length);
containerList.Add(new UriContainer()
{
Parent = sorted.First(),
Children = sorted.Skip(1).ToList()
});
}
The above code will give you a structure like this:
http://x.com/
http://x.com/y
http://x.com/y/w
http://x.com/y/z
----------------------
http://a.com/b/c
http://a.com/b/c/d
http://a.com/b/c/e
----------------------
This code has very little error prevention, you might want to make sure items are not null and such but it at least gives you a starting point.
Fiddle here

Create json in UWP without JSON.Net

I am trying to create a json formatted string using c# in UWP without JSON.Net, but I am just not understanding how to get there. Let's say I wanted to create the following json dynamically:
[{"id":130},{"id":131},{"id":132},{"id":133},{"id":134}]
From everything I have read, it would seem that I need a class that defines the content of my json. For example:
class accountTypes
{
public int id { get; set; }
public string type { get; set; }
}
From there, it would seem that I only need to create a list of type "accountTypes" and then add each "id" to the list.
List<accountTypes> jsonList = new List<accountTypes>();
int numOfChildren = AccountTypesList.Children.Count;
for (int i = 0; i < numOfChildren; i++)
{
if (((CheckBox)AccountTypesList.Children[i]).IsChecked == true)
{
jsonList.Add(new accountTypes() { id = (int)(double)((CheckBox)AccountTypesList.Children[i]).Tag });
}
}
While I am 99% sure that the above code is very flawed, it does not crash on me, so that is a start at least. What I am struggling with now though is how I would serialize the list "jsonList". Everything I have read thus far either points to JSON.net or the JavaScriptSerializer Class, and not Windows.Data.Json. If I could see a simple example on how to serialize json using Windows.Data.Json, then I could at least visualize what is going on with my list and could correct it accordingly. That being said, how do I serialize an array or a list using Windows.Data.Json?
First of all, there's no built-in JSON-serializer that handles all the mapping for you. This is exactly what JSON.NET is doing for you. Therefore, you have to take the manual and long way.
To create exactly this result:
[{"id":130},{"id":131},{"id":132},{"id":133},{"id":134}]
You have to use the JsonArray class. For example, pass your jsonList object to a method like this:
public string ToJson(List<accountTypes> objectList)
{
var jArray = new JsonArray();
foreach (var at in objectList)
{
jArray.Add(ToJson(at));
}
return jArray.ToString();
}
Whereas you use this method to create a JsonObject for your class object itself (as manual step as well):
public JsonObject ToJson(accountTypes at)
{
var jObj = new JsonObject();
jObj.SetNamedValue("id", JsonValue.CreateNumberValue(at.id));
return jObj;
}

DotLiquid: Loop through a (Wrapped) Dictionary<string, string> in for-loop in template

As far as I know, DotLiquid (using Version 1.8.0.0) does not support C# Dictionary constructs out of the box. They must be wrapped in a Drop-Object.
So I tried to adapt the Answer of Tim Jones for my use-case. Sadly, this is not working as expected, So I hope someone could show me where I'm going wrong here, for I am out of Ideas.
This is (one of) my wrapped model class containing a Dictionary:
public class LegendAdditive : Drop
{
public LegendAdditive()
{
AdditiveDict = new Dictionary<string, string>();
}
public Dictionary<string, string> AdditiveDict { get; set; }
}
The class itself is embedded in a LegendModel containing some other values:
public class LegendModel: Drop
{
...
public LegendAdditive Additives { get; set; }
...
}
As you can see, all the Classes are wrapped to be a Drop, which as I know is a prerequisite for using Dictionaries (Implementing ILiquidizable and so on).
In a converter, this Model is filled like this:
public DotLiquid.Drop GetModel(MyObject plan)
{
...
var LegendAdditives = new LegendAdditive();
//dbLegend.Additives is a Dictionary<string, string> itself.
if (dbLegend.Additives.Any())
foreach (var additive in dbLegend.Additives.OrderBy(a => a.Key))
LegendAdditives.AdditiveDict.Add(additive.Key, additive.Value);
...
LegendModel model = new LegendModel
{
...
Additives = LegendAdditives,
...
};
return model;
}
And in a class ConvertToPdf, I have a ConvertTemplate Method like this, parsing the template:
public static string ConvertTemplate(ITemplateFileFactory templateFilePathFactory IDropModelConverter modelConverter, MyObject mplan)
{
//reading my filepath out of the factory here...
DotLiquid.Template.NamingConvention = new DotLiquid.NamingConventions.CSharpNamingConvention();
Template templateObj = Template.Parse(template); // Parses and compiles the template
Drop plan = modelConverter.GetModel(mplan);
Hash hashedValues = Hash.FromAnonymousObject(new { plan });
string ret = templateObj.Render(hashedValues);
return ret;
}
And finally in my Templatefile, I try to get the Values of this Dictionary like this:
<div>
<dl>
{% for add in plan.Additives.AdditiveDict %}
<dt>{{add.Key}}</dt>
<dd>{{add.Value}}</dd>
{% endfor %}
</dl>
</div>
Now the file is parsing correctly, but all I get for now is this output when I try to access the Dictionaryvalues in my loop:
Liquid syntax error: Object '[18, Stärke]' is
invalid because it is neither a built-in type
nor implements ILiquidizable
Now it seems that I actually get the correct Values in my Template.Parse Method. I'm just not getting them out of my structure, because...? Any help is appreciated. To be honest, I think I am missing something fundamentally here.
The problem is that KeyValuePair<T>, which you're trying to access the Key and Value properties of, is neither a Drop nor implements ILiquidizable.
If you want to loop through the items in your dictionary like that, you'll have to create a KeyValueDrop wrapper, and expose a List of that, instead of a dictionary.

Dynamically deserializing to a property in RestSharp

I am playing with the Harvest API and I'm trying to automatically map the entities as easy as possible, unfortunately when I do a request like GET /projects it generates a result like so:
[{
project: {
name: "Test"
}
},
{
project: {
name: "Test 2"
}]
In RestSharp, I can't directly do this:
client.Execute<List<Project>>(request)
Because it is going to look for a property called Project. So I have to make another class that has that property, and call it like this:
client.Execute<List<ProjectContainer>>(request)
I don't want to make a 'container' class for every entity, so I thought I found a clever solution to make one class I can use on all:
public class ListContainer<T> where T : IHarvestEntity
{
public T Item { get; set; }
}
But, of course, the deserializer has no idea it needs to map the entity name (or "Project") to the property Item. In the restsharp documentation I found that I could use [DeserializeAs(Name = "CustomProperty")] to tell the deserializer which field to map to this property. However, attributes do only allow constants, which means I can't do:
[DeserializeAs(Name = typeof(T).FullName)]
public T Item { get; set; }
Does anyone know a clever solution to this? So i don't have to create 10 different container classes?
I suggest you use the XPath equivalent for Json. With Json.NET you can parse the string and create a dynamic object.
With SelectToken you can query values, or using Linq.
The code looks something like this (I did not test it):
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
JObject o = JObject.Parse(content);
IList<string> projectNames = o.SelectToken("project").Select(s => (string)s.name).ToList();
You can code the paths or configure the paths anyway you like.
--- Edit ---
Here's an example that I tested, converting the json string to a list of projects.
var projects = JArray.Parse(response.Content).Select(r => new Project(r["project"]["name"].Value<string>())).ToList();
To keep it really simple, you can use List<dynamic> and access the property/properties by name with a one-liner.
var names = client.Execute<List<dynamic>>(request).Data.Select(
item => item["project"]["name"]).ToList(); // list of names
If this is not sufficient, then you could improvise your own mapper and extract a collection of e.g. Project instances:
var projects = client.Execute<List<dynamic>>(request).Data.Select(
item => Map<Project>(item)).ToList(); // list of Project instances
where Map method could be something like
public T Map<T>(dynamic item) where T : class
{
// inline for clarity
var mappings = new Dictionary<Type,Func<dynamic,object>>
{
{ typeof(Project), map => new Project(map["project"]["name"]) }
};
return (T)mappings[typeof(T)].Invoke(item);
}
given Project is defined as
public class Project
{
public Project(string name)
{
Name = name;
}
public string Name { get; set; }
}

Categories

Resources