Parse Json Object - c#

I have an List error Entity which I used to pass errorId and error message to the UI layer.
public class ErrorEntity
{
public int ErrorId
{
get;
set;
}
public string ErrorMessage
{
get;
set;
}
}
}
I send the object to the Javascript I am serializing it to JSON.
The Json I am getting after serialization look like
[{"ErrorId":1,"ErrorMessage":"Test has not been prepared for tag EP105"},{"ErrorId":2,"ErrorMessage":"Test has not been prepared for tag EP105"}]
Now I need to parse this Json string to show the error message to the user. Please let me know how can I parse it. Do I need to write a for loop to traverse with in it.
EDIT In my master page I am trying to parse it.
function ShowErrorMsg(jsonObject) {
for (i = 0; i < jsonObject.Object.length; i++) { //Object is undefined here.
alert(jsonObject.Object.ErrorMessage);
}
}

Prefer JSON.parse() if it's available:
var jsonArray = JSON.parse(serializedString);
window.alert(jsonArray[0].ErrorMessage);
Fall back to eval() otherwise:
var jsonArray = eval(serializedString);
window.alert(jsonArray[0].ErrorMessage);

Try Json.NET

There is support in most browsers for parsing json, I recommend to use jQuery for this - you also can take a look at this
Be aware - Its better to use a library - and not using JS for this (JS is from the devil ;) )

Related

How to deserialize a json string in C# to the correct type, without deserializing twice

I have the following code:
private async Task ResponseReceived(Stream inputStream) {
using var reader = new StreamReader(inputStream);
var message = await reader.ReadToEndAsync();
var obj = JsonSerializer.Deserialize<BaseMessage>(message);
Console.WriteLine($"Message Type Received: {obj?.EventType}");
}
To which all message classes extend. The BaseMessage class contains a single property: EventType that exists in every json string deserialization.
public class BaseMessage
{
[JsonPropertyName("e")] public string EventType { get; init; }
}
The EventType provides information on the received json structure, to which I want to be able to trigger an event which publishes the correct object type based on the EventType.
The simplest solution I can think of is to do a switch case and deserialize a second time into the correct type, and then publish the event. However this poses 2 problems:
Switch case, requires coding for all the possible EventTypes (which is at least 20 currently, and could expand to many more).
Deserialization a second time, creates additional overhead in processing (both in memory and speed) where it is processing thousands of messages per second.
Is there a better way to optimize this either via a design pattern, or other way to handle it to avoid the above two concerns? I am currently using .NET Core 5, and System.Text.Json (rather than Newtonsoft Json library). I would prefer to stick with the Microsoft library, but am flexible if need to switch to Newtonsoft.
for the first problem, if EventType contains also the namespace, you can deserialize with
var objBase = JsonSerializer.Deserialize<BaseMessage>(message);
var objSpecific = JsonSerializer.Deserialize(message, Type.GetType(objBase.EventType));
so you don't need a switch.
for the second problem there is a solution, but it's breakable.
You can search for the class type inside the message.
var message = JsonSerializer.Serialize(new BaseMessage() { EventType = (typeof(A)).ToString() });
var typeString = Regex.Match(message, "\"e\":\"(.*?)\"").Groups[1];
var objSpecific = JsonSerializer.Deserialize(message, Type.GetType(typeString.Value));
if you are not forced I do not recommend it, because you can change the property name for example and you can find an error at run time or with a test.

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.

Unexpected character encountered while parsing value

Currently, I have some issues. I'm using C# with Json.NET. The issue is that I always get:
{"Unexpected character encountered while parsing value: e. Path '', line 0, position 0."}
So the way I'm using Json.NET is the following. I have a Class which should be saved. The class looks like this:
public class stats
{
public string time { get; set; }
public string value { get; set; }
}
public class ViewerStatsFormat
{
public List<stats> viewerstats { get; set; }
public String version { get; set; }
public ViewerStatsFormat(bool chk)
{
this.viewerstats = new List<stats>();
}
}
One object of this class will be filled and saved with:
File.WriteAllText(tmpfile, JsonConvert.SerializeObject(current), Encoding.UTF8);
The saving part works fine and the file exists and is filled. After that the file will be read back into the class with:
try
{
ViewerStatsFormat current = JsonConvert.DeserializeObject<ViewerStatsFormat>(tmpfile);
//otherstuff
}
catch(Exception ex)
{
//error loging stuff
}
Now on the current= line comes the exception:
{"Unexpected character encountered while parsing value: e. Path '', line 0, position 0."}
I don't know why this comes. The JSON file is the following -> Click me I am the JSON link
Does anyone have any ideas?
Possibly you are not passing JSON to DeserializeObject.
It looks like from File.WriteAllText(tmpfile,... that type of tmpfile is string that contain path to a file. JsonConvert.DeserializeObject takes JSON value, not file path - so it fails trying to convert something like #"c:\temp\fooo" - which is clearly not JSON.
I solved the problem with these online tools:
To check if the Json structure is OKAY: http://jsonlint.com/
To generate my Object class from my Json structure: https://www.jsonutils.com/
The simple code:
RootObject rootObj= JsonConvert.DeserializeObject<RootObject>(File.ReadAllText(pathFile));
In my case, the file containing JSON string had BOM. Once I removed BOM the problem was solved.
I experienced the same error in my Xamarin.Android solution.
I verified that my JSON was correct, and noticed that the error only appeared when I ran the app as a Release build.
It turned out that the Linker was removing a library from Newtonsoft.JSON, causing the JSON to be parsed incorrectly.
I fixed the error by adding Newtonsoft.Json to the Ignore assemblies setting in the Android Build Configuration (screen shot below)
JSON Parsing Code
static readonly JsonSerializer _serializer = new JsonSerializer();
static readonly HttpClient _client = new HttpClient();
static async Task<T> GetDataObjectFromAPI<T>(string apiUrl)
{
using (var stream = await _client.GetStreamAsync(apiUrl).ConfigureAwait(false))
using (var reader = new StreamReader(stream))
using (var json = new JsonTextReader(reader))
{
if (json == null)
return default(T);
return _serializer.Deserialize<T>(json);
}
}
Visual Studio Mac Screenshot
Visual Studio Screenshot
I have also encountered this error for a Web API (.Net Core 3.0) action that was binding to a string instead to an object or a JObject. The JSON was correct, but the binder tried to get a string from the JSON structure and failed.
So, instead of:
[HttpPost("[action]")]
public object Search([FromBody] string data)
I had to use the more specific:
[HttpPost("[action]")]
public object Search([FromBody] JObject data)
This issue is related to Byte Order Mark in the JSON file. JSON file is not encoded as UTF8 encoding data when saved. Using File.ReadAllText(pathFile) fix this issue.
When we are operating on Byte data and converting that to string and then passing to JsonConvert.DeserializeObject, we can use UTF32 encoding to get the string.
byte[] docBytes = File.ReadAllBytes(filePath);
string jsonString = Encoding.UTF32.GetString(docBytes);
I had the same problem with webapi in ASP.NET core, in my case it was because my application needs authentication, then it assigns the annotation [AllowAnonymous] and it worked.
[AllowAnonymous]
public async Task <IList <IServic >> GetServices () {
        
}
I ran into this issue and it ended up being because of BOM characters in my input string.
Here's what I ended up doing:
String.Trim(new char[] { '\uFEFF', '\u200B' });
This resolved the issue for me.
In my case, I was getting an error on JsonConvert.PopulateObject().
My request was returning JSON that was wrapped in an extra pair of '[ ]' brackets, making my result an array of one object rather than just an object. Here's what I did to get inside these brackets (only for that type of model):
T jsonResponse = new T();
var settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.DateTimeOffset,
NullValueHandling = NullValueHandling.Ignore,
};
var jRslt = response.Content.ReadAsStringAsync().Result;
if (jsonResponse.GetType() == typeof(myProject.Models.MyModel))
{
var dobj = JsonConvert.DeserializeObject<MyModel[]>(jRslt);
var y = dobj.First();
var szObj = JsonConvert.SerializeObject(y);
JsonConvert.PopulateObject(szObj, jsonResponse, settings);
}
else
{
JsonConvert.PopulateObject(jRslt, jsonResponse);
}
If you are using downloading data using url...may need to use
var result = client.DownloadData(url);
In my scenario I had a slightly different message, where the line and position were not zero.
E. Path 'job[0].name', line 1, position 12.
This was the top Google answer for the message I quoted.
This came about because I had called a program from the Windows command line, passing JSON as a parameter.
When I reviewed the args in my program, all the double quotes got stripped.
You have to reconstitute them.
I posted a solution here. Though it could probably be enhanced with a Regex.
I had a similar error and thought I'd answer in case anyone was having something similar. I was looping over a directory of json files and deserializing them but was getting this same error.
The problem was that it was trying to grab hidden files as well. Make sure the file you're passing in is a .json file. I'm guessing it'll handle text as well. Hope this helps.
I had simular problem. In my case the problem was in DateTime format. It was just numbers and it is also know as EpochFormat or UnixTimestamp.
A part from my JSON:
"direction": "outbound",
"date_archive": 1554691800224,
"date_doc": 1524700800000,
"date_sent": 1524704189000,
"date_received": 1524704189000,
"date_store_till": 1712544600224,
So I've used an attribute like this:
[JsonProperty("date_received")]
[JsonConverter(typeof(MicrosecondEpochConverter))]
public DateTime? DateReceived { get; set; }
You can find MicrosecondEpochConverter code here: https://stackoverflow.com/a/19972214/4324624
I faced similar error message in Xamarin forms when sending request to webApi to get a Token,
Make sure all keys (key : value) (ex.'username', 'password', 'grant_type') in the Json file are exactly what the webApi expecting, otherwise it fires this exception.
Unhandled Exception: Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 0, position 0
Please check the model you shared between client and server is same. sometimes you get this error when you not updated the Api version and it returns a updated model, but you still have an old one. Sometimes you get what you serialize/deserialize is not a valid JSON.
In my case, it was the lack of a default parameterless constructor !!!
In my case, I was calling the async service method without using await, so before Task is completed I was trying to return the result!
Suppose this is your json
{
"date":"11/05/2016",
"venue": "{\"ID\":12,\"CITY\":Delhi}"
}
if you again want deserialize venue, modify json as below
{
"date":"11/05/2016",
"venue": "{\"ID\":\"12\",\"CITY\":\"Delhi\"}"
}
then try to deserialize to respective class by taking the value of venue
This error occurs when we parse json content to model object. Json content type is string.
For example:
https://dotnetfiddle.net/uFClKj
Some times, an api that we call may return an error. If we do not check the response status, but proceed to parse the response to model, this issue will occur.
When I encountered a similar problem, I fixed it by substituting &mode=xml for &mode=json in the request.

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.

Persist data using JSON

I'm tryping to use JSON to update records in a database without a postback and I'm having trouble implementing it. This is my first time doing this so I would appreciate being pointed in the right direction.
(Explanation, irrelevant to my question: I am displaying a list of items that are sortable using a jquery plugin. The text of the items can be edited too. When people click submit I want their records to be updated. Functionality will be very similar to this.).
This javascript function creates an array of the objects. I just don't know what to do with them afterwards. It is called by the button's onClick event.
function SaveLinks() {
var list = document.getElementById('sortable1');
var links = [];
for (var i = 0; i < list.childNodes.length; i++) {
var link = {};
link.id = list.childNodes[i].childNodes[0].innerText;
link.title = list.childNodes[i].childNodes[1].innerText;
link.description = list.childNodes[i].childNodes[2].innerText;
link.url = list.childNodes[i].childNodes[3].innerText;
links.push(link);
}
//This is where I don't know what to do with my array.
}
I am trying to get this to call an update method that will persist the information to the database. Here is my codebehind function that will be called from the javascript.
public void SaveList(object o )
{
//cast and process, I assume
}
Any help is appreciated!
I have recently done this. I'm using MVC though it shouldn't be too different.
It's not vital but I find it helpful to create the contracts in JS on the client side and in C# on the server side so you can be sure of your interface.
Here's a bit of sample Javascript (with the jQuery library):
var item = new Item();
item.id = 1;
item.name = 2;
$.post("Item/Save", $.toJSON(item), function(data, testStatus) {
/*User can be notified that the item was saved successfully*/
window.location.reload();
}, "text");
In the above case I am expecting text back from the server but this can be XML, HTML or more JSON.
The server code is something like this:
public ActionResult Save()
{
string json = Request.Form[0];
var serializer = new DataContractJsonSerializer(typeof(JsonItem));
var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(json));
JsonItem item = (JsonItem)serializer.ReadObject(memoryStream);
memoryStream.Close();
SaveItem(item);
return Content("success");
}
Hope this makes sense.
You don't use CodeBehind for this, you use a new action.
Your action will take an argument which can be materialized from your posted data (which, in your case, is a JavaScript object, not JSON). So you'll need a type like:
public class Link
{
public int? Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Url { get; set; }
}
Note the nullable int. If you have non-nullable types in your edit models, binding will fail if the user does not submit a value for that property. Using nullable types allows you to detect the null in your controller and give the user an informative message instead of just returning null for the whole model.
Now you add an action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult DoStuff(IEnumerable<Link> saveList)
{
Repository.SaveLinks(saveList);
return Json(true);
}
Change your JS object to a form that MVC's DefaultModelBinder will understand:
var links = {};
for (var i = 0; i < list.childNodes.length; i++) {
links["id[" + i + "]"] = list.childNodes[i].childNodes[0].innerText;
links["title[" + i + "]"] = list.childNodes[i].childNodes[1].innerText;
links["description[" + i + "]"] = list.childNodes[i].childNodes[2].innerText;
links["url[" + i + "]"] = list.childNodes[i].childNodes[3].innerText;
}
Finally, call the action in your JS:
//This is where I don't know what to do with my array. Now you do!
// presumes jQuery -- this is much easier with jQuery
$.post("/path/to/DoStuff", links, function() {
// success!
},
'json');
Unfortunately, JavaScript does not have a built-in function for serializing a structure to JSON. So if you want to POST some JSON in an Ajax query, you'll either have to munge the string yourself or use a third-party serializer. (jQuery has a a plugin or two that does it, for example.)
That said, you usually don't need to send JSON to the HTTP server to process it. You can simply use an Ajax POST request and encode the form the usual way (application/x-www-form-urlencoded).
You can't send structured data like nested arrays this way, but you might be able to get away with naming the fields in your links structure with a counter. (links.id_1, links.id_2, etc.)
If you do that, then with something like jQuery it's as simple as
jQuery.post( '/foo/yourapp', links, function() { alert 'posted stuff' } );
Then you would have to restructure the data on the server side.

Categories

Resources