invalid JSON generated by default Restsharp JSON serialiser - c#

My code is below. When I post a JSON body that has \v in it, the server receives JSON that it cannot parse. Any help on how to make it work?
EDIT: well, the argument about my server not being able to parse it is weak, but http://jsonlint.com/ complains about it too. : )
in my emacs it looks like this:
{"key":"a^Kb"}
where ^K I think is a single character.
code:
using RestSharp;
using System;
using System.Collections.Generic;
namespace testapp
{
class Program
{
static void Main(string[] args)
{
var client = new RestClient();
var request = new RestRequest();
request.Method = Method.POST;
request.RequestFormat = DataFormat.Json;
request.Resource = "http://example.com/";
var data = new Dictionary<string, string>();
data.Add("key", "a\vb");
request.AddBody(data);
var response = client.Execute<Dictionary<string, string>>(request);
}
}
}

The default RestSharp JSON serializer serializes this as equivalent to the C# string "{\"key\":\"a\vb\"}"; that is, it sends the \v as a raw byte (0b) over the wire. This is why your server has trouble reading it. I'm unsure if this is legal JSON, but in any case there are ways to escape such a character to avoid issues.
I'd recommend using Json.NET to de/serialize your JSON. If you use the the following class (originally part of RestSharp) as your serializer, it will use Json.NET and should work correctly, since it will encode the \v as \u000b over the wire. The code (sans comments, and renamed for clarity) is copied here for reference:
public class JsonNetSerializer : ISerializer
{
private readonly Newtonsoft.Json.JsonSerializer _serializer;
public JsonNetSerializer()
{
ContentType = "application/json";
_serializer = new Newtonsoft.Json.JsonSerializer
{
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Include,
DefaultValueHandling = DefaultValueHandling.Include
};
}
public JsonNetSerializer(Newtonsoft.Json.JsonSerializer serializer)
{
ContentType = "application/json";
_serializer = serializer;
}
public string Serialize(object obj)
{
using (var stringWriter = new StringWriter())
{
using (var jsonTextWriter = new JsonTextWriter(stringWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
jsonTextWriter.QuoteChar = '"';
_serializer.Serialize(jsonTextWriter, obj);
var result = stringWriter.ToString();
return result;
}
}
}
public string DateFormat { get; set; }
public string RootElement { get; set; }
public string Namespace { get; set; }
public string ContentType { get; set; }
}
To use it, add this line:
request.JsonSerializer = new JsonNetSerializer();
And it will serialize like:
{
"key": "a\u000bb"
}
Which is perfectly valid according to JSONLint.

Related

How can i make a flat object by removing keys in C#?

I am really not sure if this could be achievable, How can i remove some nested keys in an Object and make the object very flat. I have a dynamic object as follows,
EventData": { "ChangeSet": { "Change": {
"changes": [
] } } }
and i want to change the above to
EventData": { [] }
is this can be achieved in C#?
Use the NewtonSoft.JSon package.. Following code does the trick. I made it a string array because I do not know what you need but you can change this to your liking.
const string complex = "{\"EventData\": { \"ChangeSet\": { \"Change\": { \"changes\" : [ ]}}}}";
Call to method:
string simple = returnSimpleObject(complex);
public class SerializeData
{
public string[] EventData { get; set; }
}
private static string returnSimpleObject(string Json)
{
JObject jobject = JObject.Parse(Json);
JToken tEventData = jobject.SelectToken("EventData");
SerializeData myEvent = tEventData.ToObject<SerializeData>();
JToken tchanges = jobject.SelectToken("EventData.ChangeSet.Change.changes");
myEvent.EventData = tchanges.ToObject<string[]>();
JsonSerializer serializer = new JsonSerializer();
StringWriter strWrite = new StringWriter();
JsonWriter myWriter = new JsonTextWriter(strWrite);
serializer.Serialize(myWriter, myEvent);
return strWrite.ToString();
}

Change XML opener(reader) to JSON

I have followed a good tutorial that shows how to make an Automation Framework in C# Selenium.
The config file is in XML at the moment, but I wanted some more practice and change it to a .json file.
At the moment we are using the namespace System.Xml.XPath; and my question is, are there a similar for JSON? Lets say "System.Json;" that works the same as my XML reader. So I don't need to refactor to much code, or is it unavoidably?
This is how it works at the moment.
//Initialize
ConfigReader.SetFrameworkSettings();
public class ConfigReader
{
public static void SetFrameworkSettings()
{
XPathItem aut;
string strFilename = Environment.CurrentDirectory.ToString() + "\\Config\\GlobalConfig.xml";
FileStream stream = new FileStream(strFilename, FileMode.Open);
XPathDocument document = new XPathDocument(stream);
XPathNavigator navigator = document.CreateNavigator();
//Get XML Details and pass it in XPathItem type variables
aut = navigator.SelectSingleNode("AutoFramework/RunSettings/AUT");
Settings.AUT = aut.Value.ToString();
}
}
public class Settings
{
public static string AUT { get; set; }
}
Would be awesome if you could just change this two lines
XPathDocument document = new XPathDocument(stream);
XPathNavigator navigator = document.CreateNavigator()
And the XpathItem
Cheers
I would recommend using Newtonsoft.Json which is available from Nuget.
To "reuse" your current code you would have to make some basic SettingsConverter first:
public static class SettingsConverter
{
public static string FromXmlToJson(string xml)
{
Settings settings = null;
// read your xml file and assign values to the settings object
// now you can "serialize" settings object into Json
return JsonSerialization.Serialize(settings);
}
public static string FromJsonToXml(string json)
{
Settings settings = JsonSerialization.Deserialize<MeSettings>(json);
// save settings using your "xml" serialization
return xmlString; // return xml string
}
}
To use these methods I'm using this JsonSerialization helper class :
public static class JsonSerialiation
{
public static string Serialize<T>(T obj)
{
using (MemoryStream stream = new MemoryStream())
{
using (JsonTextWriter writer = new JsonTextWriter(new StreamWriter(stream))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serializer(writer, obj);
writer.Flush();
stream.Position = 0;
using (StreamReader reader = new StreamREader(stream))
{
return reader.ReadToEnd();
}
}
}
}
public static T Deserialize<T>(string jsonString)
{
using (JsonTextReader reader = new JsonTextReader(new StringReader(str)))
{
JsonSerializer serializer = new JsonSerializer();
return serializer.Deserialize<T>(reader)
}
}
}
Above example requires from you to change your Settings class from static :
public class Settings
{
public static string AUT { get; set; }
}
To instance :
public class Settings
{
public string AUT { get; set; }
}
If you prefer to keep it as static. You should use JObject from Newtonsoft.Json library :
JObject obj = JObject.Parse(jsonString);
Settings.AUT = obj.SelectToken("AUT").Value<string>();
You can always use JsonConvert.Serialize<T>() and JsonConvert.Deserialize<T>() methods instead of the JsonSerialization helper class that I've made but in my opinion the less control you have over your code the bigger the problems will be.

Converting JSON to C# class

I have this JSON string:
[{"fkp_keyword":"CLI_RID"},
{"fkp_keyword":"DOC_NAME"},
{"fkp_keyword":"FILENAME"},
{"fkp_keyword":"PRINT_DATE"},
{"fkp_keyword":"EVENT_CODE"},
{"fkp_keyword":"CONFL_RID"},
{"fkp_keyword":"PROGRAM_CODE"},
{"fkp_keyword":"CES"},
{"fkp_keyword":"DISTR"},
{"fkp_keyword":"REC_DATE"},
{"fkp_keyword":"REC_RID"},
{"fkp_keyword":"PFL_RID"},
{"fkp_keyword":"DES"},
{"fkp_keyword":"CER_RID"}
]
I need to convert it into a List of the class kw below.
Definitions:
public class kw
{
public string fkp_keyword { get; set; }
}
But this code:
List<kw> header = new List<kw>();
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string result = client.DownloadString(parms);
header = JsonConvert.DeserializeObject<List<kw>>(result);
}
The call returns the JSON string above but when trying to convert it, the code above returns this exception:
Error converting value to type 'System.Collections.Generic.List[LA.Models.kw]
Update
I changed the definitions to this:
public class kwList
{
public kw[] Property1 { get; set; }
}
public class kw
{
public string fkp_keyword { get; set; }
}
and the code to this:
kwList header = new kwList();
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string result = client.DownloadString(parms);
header = JsonConvert.DeserializeObject<kwList>(result);
}
But now I'm getting this Exception:
Could not cast or convert from System.String to LicenseeArchive.Models.kwList.
What am I doing wrong?
For whatever reason, it appears that the JSON string returned by that URL is double-serialized. That is, it contains extra backslashes to escape all the quotes, which then prevents it from being deserialized properly to an array of objects. That is why you are getting an error.
To work around the problem, you can deserialize it twice: first to unescape the JSON, the second to do the "real" deserialization to your classes. Longer term, you may also wish to contact the provider of the API to see if they will fix their JSON.
List<kw> header = new List<kw>();
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string result = client.DownloadString(parms);
string unescapedJson = JsonConvert.DeserializeObject<string>(result);
header = JsonConvert.DeserializeObject<List<kw>>(unescapedJson);
}
Fiddle: https://dotnetfiddle.net/XEULdy
JSON string you provided can be loaded with your first class definition:
public class kw
{
public string fkp_keyword { get; set; }
}
Example:
string example = "[{\"fkp_keyword\":\"CLI_RID\"}, {\"fkp_keyword\":\"DOC_NAME\"}, {\"fkp_keyword\":\"FILENAME\"}]";
List<kw> kws = JsonConvert.DeserializeObject<List<kw>>(example);
Maybe you are not providing all details. Or your json string looks different.

Serializing a class to xml using RestSharp.AddBody fails

I try to add a simple test-class to a RestSharp-RestRequest via the RestRequest.AddBody-Method. I tried to serialize using both of the delivered serializers, but i could not get one of them to work (JSON-Serializations works pretty fine with just the same settings...)
This is how i do the serialization:
private void SerializationTest()
{
RestRequest request = new RestRequest();
request.XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer();
//request.XmlSerializer = new RestSharp.Serializers.XmlSerializer();
request.RequestFormat = DataFormat.Xml;
//request.RequestFormat = DataFormat.Json;
request.AddBody(new Dummy()); // uses JsonSerializer
label1.Text = request.Parameters[0].Value.ToString();
}
The dummy-class I'm using is:
private class Dummy
{
public string A = "Some string";
public string B = "Some string";
}
Using RestSharp.Serializers.XmlSerializer() I get: "<Dummy />" (missing both strings)
Using RestSharp.Serializers.DotNetXmlSerializer() I get nothing, the programm just dosen't get over the serialization-step.
Using JSON request.RequestFormat = DataFormat.Json;, everything works fine.
.
{
"A": "Some string",
"B": "Some string"
}
How do i get the class so serialize proper to XML?
Thanks for your help!
Those are fields, not properties. The underlying XmlSerializer only looks for public properties. Update it to this and it should work:
class Dummy
{
public string A { get; set; };
public string B { get; set; };
public Dummy() {
A = "Some string";
B = "Some string";
}
}
The reason the JSON one works is because it defers to JSON.NET's default serializer which (apparently) supports fields. I think this is the wrong design decision personally.

Using WebClient for JSON Serialization?

I know you can deserialize a JSON object from an HttpWebResponse using the WebClient.DownloadString() but what about the other way around? I've looked at the MSDN pages and I don't know if you can serialize to JSON objects or not, anyone know?
I think you may just have to serialize the object into JSON before using the WebClient instance. Hope this helps
var url = "...";
var json = JsonHelper.ToJson(myObject);
var response = PostJson(url, json);
Here's an example of sending JSON data from the WebClient class:
public static string PostJson(string url, string data)
{
var bytes = Encoding.Default.GetBytes(data);
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/json");
var response = client.UploadData(url, "POST", bytes);
return Encoding.Default.GetString(response);
}
}
Here is a simple helper class that uses the DataContractJsonSerializer class to serialize / deserialize object to and from JSON.
public static class JsonHelper
{
public static string ToJson<T>(T instance)
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var tempStream = new MemoryStream())
{
serializer.WriteObject(tempStream, instance);
return Encoding.Default.GetString(tempStream.ToArray());
}
}
public static T FromJson<T>(string json)
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var tempStream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
return (T)serializer.ReadObject(tempStream);
}
}
}
I use :
var json = new JavaScriptSerializer().Serialize(yourObject);

Categories