Adding object to JSON file - c#

I'm creating a software on which I added a profiles feature where the user can create profile to load his informations faster. To store these informations, I'm using a JSON file, which contains as much objects as there are profiles.
Here is the format of the JSON file when a profile is contained (not the actual one, an example) :
{
"Profile-name": {
"form_email": "example#example.com",
//Many other informations...
}
}
Here is the code I'm using to write the JSON and its content :
string json = File.ReadAllText("profiles.json");
dynamic profiles = JsonConvert.DeserializeObject(json);
if (profiles == null)
{
File.WriteAllText(jsonFilePath, "{}");
json = File.ReadAllText(jsonFilePath);
profiles = JsonConvert.DeserializeObject<Dictionary<string, Profile_Name>>(json);
}
profiles.Add(profile_name.Text, new Profile_Name { form_email = form_email.Text });
var newJson = JsonConvert.SerializeObject(profiles, Formatting.Indented);
File.WriteAllText(jsonFilePath, newJson);
profile_tr.Nodes.Add(profile_name.Text, profile_name.Text);
debug_tb.Text += newJson;
But when the profiles.json file is completely empty, the profile is successfully written, but when I'm trying to ADD a profile when another one already exists, I get this error :
The best overloaded method match for 'Newtonsoft.Json.Linq.JObject.Add(string, Newtonsoft.Json.Linq.JToken)' has some invalid arguments on the profiles.Add(); line.
By the way, you can notice that I need to add {} by a non-trivial way in the file if it's empty, maybe it has something to do with the error ?
The expected output would be this JSON file :
{
"Profile-name": {
"form_email": "example#example.com",
//Many other informations...
},
"Second-profile": {
"form_email": "anotherexample#example.com"
//Some other informations...
}
}

Okay so I found by reading my code again, so I just replaced dynamic profiles = JsonConvert.DeserializeObject(json); to dynamic profiles = JsonConvert.DeserializeObject<Dictionary<string, Profile_Name>>(json);.
But it still don't fix the non-trivial way I use to add the {} to my file...

The object the first DeserializeObject method returns is actually a JObject, but below you deserialize it as a Dictionary. You shouldn't be mixing the types, choose either one.
If you use the JObject then to add objects you need to convert them to JObjects:
profiles.Add(profile_name.Text, JObject.FromObject(new Profile_Name { form_email = form_email.Text }));
In both cases, when the profile is null you just need to initialize it:
if (profiles == null)
{
profiles = new JObject(); // or new Dictionary<string, Profile_Name>();
}

Related

JsonDocument - Read child object

I have a JSON object that I'm trying to read properties from. Here is a sample:
{"id":"335057af-a156-41c6-a0de-0cdc05856b3d",
"title":"Test 100488-100489 not included",
"code":"QWNCY47Y999",
"start":"2022-08-10T22:00:00.000Z",
"end":"2022-08-11T02:00:00.000Z",
"closeAfter":"2022-08-08T23:59:00.000Z",
"archiveAfter":"2022-11-08T22:00:00.000Z",
"timezone":"America/New_York",
"defaultLocale":"enUS",
"currency":"USD",
"registrationSecurityLevel":"Public",
"status":"Pending",
"eventStatus":"Upcoming",
"planningStatus":"In-Planning",
"testMode":true,
"planners":[{"firstName":"C","lastName":"G","email":"Noreply#events.qwerty.comx"}],
"created":"2021-06-11T09:55:57.667Z",
"lastModified":"2021-07-08T17:21:48.039Z",
"customFields":[
{"id":"f2cf4864-171f-44fa-919a-248d37e42563",
"name":"Level of Service",
"value":["Full Support"],
"type":"SingleSelect",
"order":25},
{"id":"c1539edf-a3e1-4f40-9747-e93f4fedfa5d",
"name":"Internal/External",
"value":["Internal","External"],
"type":"MultiSelect",
"order":42},
{"id":"1b525d2a-b3f8-4141-91ae-45de5ee3a2fe",
"name":"Request ID",
"value":["MRF000558"],
"type":"AutoIncrement",
"order":53}],
"category":{"name":"Conference"},
"_links":{"invitation":{"href":"http://sandbox-www.qwerty.com/d/8nqg6n/1Q"},
"agenda":{"href":"http://sandbox-www.qwerty.com/d/8nqg6n/6X"},
"summary":{"href":"http://sandbox-www.qwerty.com/d/8nqg6n"},
"registration":{"href":"http://sandbox-www.qwerty.com/d/8nqg6n/4W"}},
"virtual":false,
"format":"In-person"}
I can programmatically read string properties, but if one of the properties is another object, I can't read it.
try
{
var x1 = content2.RootElement.GetProperty("code"); // it works
var x2 = content2.RootElement.GetProperty("currency"); // it works
var x3 = content2.RootElement.GetProperty("start"); // it works
var x99 = content2.RootElement.GetProperty("summary"); // exception, key not found
var x999 = x99.GetProperty("href");
}
catch(System.Exception ex)
{
Console.WriteLine(ex.Message);
}
Ultimately, my goal is to read the summary child object and get property href.
you have a bug. "summary" goes after "_links"
this works for me
var contentObj = JObject.Parse(content);
var href = contentObj["_links"]["summary"]["href"];
output
http://sandbox-www.qwerty.com/d/8nqg6n
for you I guess it could be
var x9 = content2.RootElement.GetProperty("_links");
var x99 = x9.GetProperty("summary");
var x999 = x99.GetProperty("href").ToString();
//or just
var x999 = content2.RootElement.GetProperty("_links").GetProperty("summary").GetProperty("href").ToString();
Unless this "but if one of the properties is another object, I can't read it." means that you don't have a well defined format for your JSON file, just create an object for your JSON file and deserialize it. Then you can access it directly via that objects property.

Using Json to Create FormDialog

I am trying to build user and conversation specific dialogs using json schema and I have the LINQ queries generating the json perfectly. If I save a sample of the json to disk and use it like the annotatedsandwich example where it is read from a file on disk, it works great. The json is unique per user and conversation and instead of writing to disk I want to use it in memory. I do not see how to pass the json string to the BuildJsonForm method or alternately how to get the userID information in the BuildJsonForm method in order to generate the json based on the user and conversation. I know I am missing something that will let me do this but I am not finding it. Any assistance with how this should be done would be appreciated. Thank you.
Instead of doing (using the AnnotatedSandwich code)
FormDialog.FromForm(SandwichOrder.BuildJsonForm)
You could just build the BuildFormDelegate and pass your parameters:
string schema = "your jsonform schema";
BuildFormDelegate<JObject> formDelegate = () => SandwichOrder.BuildJsonForm(schema);
FormDialog.FromForm(formDelegate)
Create a custom form builder to which you pass your custom form json schema
[Serializable]
public class CustomFormBuilder
{
public string FormJson { get; set; }
public CustomFormBuilder(string formJson)
{
FormJson = formJson;
}
public IForm<JObject> BuildJsonForm()
{
var schema = JObject.Parse(FormJson);
var form = new FormBuilderJson(schema)
.AddRemainingFields()
.Build();
return form;
}
}
Use as follows (where formJson is your user specific form)
var formBuilder = new CustomFormBuilder(formJson);
var jsonFormDialog = FormDialog.FromForm(
formBuilder.BuildJsonForm,
FormOptions.PromptInStart);
This will avoid the ClosureCaptureExcept‌​ion.

Initialize nested classes in a list

I have a list called OrderProductAttributes and I initialzed it like the following:
OrderProductAttributes = new List<OrderProductAttribute>
{orderProductAttribute }
I have to two other nested classes in the OrderProductAttribute and I am trying to instantiate them like the following:
static OrderProductAttribute orderProductAttribute = new OrderProductAttribute()
{
productAttribute = new ProductAttribute()
{
attributeType=new AttributeType()
}
};
I want to see them as a json file and once I open the output json file I see the following:
"OrderProductAttributes":{"["productAttribute":null]"}
I was wondering why the attributeType was not created in the productAttribute since I have initiated it already?
I was expecting to see
"OrderProductAttributes":{"["productAttribute":"attributeType":""]"}

ServiceStack - dictionary to csv

In my project I use ServiceStack to allow user to export data in csv format. It's ServiceStack that makes the job but it always sorts my dictionary by alphabetical and I don't want that. I want that my csv file have his columns in exact order that I inserted my data in the dictionary.
There is a way to configure ServiceStack to don't make this sort ?
My dictionary :
var excelResult = new Dictionary<string, string>();
excelResult["Id"] = x.Id.ToString();
excelResult["IBS Account Id"] = x.IBSAccountId.ToString(CultureInfo.InvariantCulture);
excelResult["IBS Order Id"] = x.IBSOrderId.ToString();
And in my csv file, instead of "Id, IBS Account Id,IBS Order Id" I have "IBS Account Id,IBS Order Id,Id"
Thank you very much !!
Here is how to unregister the default 'text/csv' content-type and serializer.
In AppHost.cs,
using ServiceStack.Common;
In AppHost Configure()...
SetConfig(new EndpointHostConfig
{
EnableFeatures = Feature.All.Remove(Feature.Csv),
});
Your apphost will no longer do any special handling for text/csv. At that point, you should be able to register it again as you wish, as explained in How to register your own custom format with ServiceStack.
Substitute your TapasSerializer for CsvSerializer and you should be good.
I discovered a clue how to do it from this SO answer.
Finally, I discover it's impossible(?) to override or custom ServiceStack CsvSerializer.
So, my solution (because I have to do something after all) : Create a new custom type, serialize it and write it in a csv file :)
Step 1 : (AppHOst.cs) Register my new type "tapas" (because I like tapas but I don't think my lead will be ok with that :p)
ContentTypeFilters.Register("text/x-tapas",
TapasSerializer.SerializeToStream, TapasSerializer.DeserializeFromStream);
Step 2 : (AppHOst.cs) Configure the response for the creation of the file
ResponseFilters.Add((req, res, dto) =>
{
if (req.ResponseContentType == "text/x-tapas")
{
res.AddHeader(HttpHeaders.ContentDisposition,
string.Format("attachment;filename={0}.csv", req.OperationName));
}
});
Step 3 : (myPage.handlebars) Swap csv with my new type in my request link (in java for my project)
<li>{{localize "ExportOrders"}}</li>
Step 4 : Your Tapas Serializer !
public class TapasSerializer
{
static TapasSerializer()
{
}
public static void SerializeToStream(IRequestContext requestContext, object response, Stream stream)
{
//TO DO
}
public static object DeserializeFromStream(Type type, Stream stream)
{
//TO DO
}
}
Thank you for reading !

storing JSON data in db

I'm trying to store data from fb wall into database.
My *.cs code
public ActionResult GetWall()
{
JSONObject wallData = helper.Get("/me/feed");
if (wallData != null)
{
var data = wallData.Dictionary["data"];
List<JSONObject> wallPosts = data.Array.ToList<JSONObject>();
ViewData["Wall"] = wallPosts;
}
return View("Index");
}
Which gets posts from fb wall.
And then I have an *.aspx file, which "breaks" my wallposts into pieces (objects) or whatever you like to call them.
foreach (Facebook.JSONObject wallItem in wallPosts)
{
string wallItemType = wallItem.Dictionary["type"].String;
//AND SO ON...
What i'm trying to say is that I can access to elements inside fb JSON.
Is there a way i can access to the JSON elements inside *.cs file.
Or is there a way I can store elements inside the *.aspx file to db?
And if its possible, I would like to know how. =)
Thanks for help
Don't use the SDK. Fetch the JSON Data using HttpWebRequest and then Deserialize it using System.Runtime.Serialization.Json.DataContractJsonSerializer. You just have to Create a class with same properties returned in JSON data. See the example below
string Response = Utilities.HttpUtility.Fetch("https://graph.facebook.com/me?access_token=" + AccessToken, "GET", string.Empty);
using (System.IO.MemoryStream oStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Response)))
{
oStream.Position = 0;
return (Models.FacebookUser)new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Models.FacebookUser)).ReadObject(oStream);
}
I'm not familiar with the facebook API and the question isn't too clear, but I assume that the string wallItemType is itself a JSON string, and you wish to parse it.
I'd use the Json.Net library to parse this.
using Newtonsoft.Json;
//your code as above
foreach (Facebook.JSONObject wallItem in wallPosts)
{
string wallItemType = wallItem.Dictionary["type"].String;
//I assume wallItemType is a JSON string {"name":"foobar"} or similar
JObject o = JObject.Parse(wallItemType);
string name = (string)o["name"]; //returns 'foobar'
//and so on
you can also use the Json.Net to deserialize to a custom type. This custom type could be mapped to a SQL database using NHibernate.
If you wish to store the entire json string in a database, then you could use a document database such as CouchDB.

Categories

Resources