Using WebClient for JSON Serialization? - c#

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);

Related

How to cache an array using IDistributedCache?

I have a project that is written in C# on the top of ASP.NET Core 6 framework.
I need to cache data of type AppraisalResult[] using IDistributedCache.
I created the following class:
public class AppraisalCacheService : IAppraisalCacheService
{
private readonly IDistributedCache _distributedCache;
private readonly JsonSerializer _serializer;
public AppraisalCacheService(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
_serializer = new JsonSerializer();
}
public async Task<AppraisalResult[]> GetAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
var data = await _distributedCache.GetAsync(key);
if (data != null)
{
using MemoryStream ms = new MemoryStream(data);
using BsonDataReader reader = new BsonDataReader(ms);
return _serializer.Deserialize<AppraisalResult[]>(reader);
}
return null;
}
public async Task RemoveAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
await _distributedCache.RemoveAsync(key);
}
public async Task StoreAsync(AppraisalResult[] results, ....)
{
// logic removed for simplicity
var key = GetKey(..);
using MemoryStream ms = new MemoryStream();
using BsonDataWriter writer = new BsonDataWriter(ms);
_serializer.Serialize(writer, results);
await _distributedCache.SetAsync(key, ms.ToArray(), new DistributedCacheEntryOptions()
{
SlidingExpiration = TimeSpan.FromDays(7),
AbsoluteExpiration = DateTime.Now.AddDays(30),
});
}
private string GetKey(...)
{
// logic removed for simplicity
return "custom-key....";
}
}
The StoreAsync() method seems to be working fine. But, when I try to cast the cached value back into AppraisalResult[] it fails with the following error
{"Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'AppraisalResult[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath '0'."}
UPDATED
When trying to ready from the cache prior deserializeing I am getting an error. Here is the code that I tried
var data = await _distributedCache.GetAsync(key);
if (data != null)
{
using MemoryStream ms = new MemoryStream(data);
using BsonDataReader reader = new BsonDataReader(ms);
var dd = reader.ReadAsBytes();
}
The line reader.ReadAsBytes() throw the following exception before I deserialize:
{"Error reading bytes. Unexpected token: StartObject. Path '0'."}
It turned out that this is a limitation in Bson. You can't deserilize directly yo array object. The workaround was to create an object that contains the array property
public class AppraisalResultObj
{
public AppraisalResult[] Results { get; set; }
}
public class AppraisalCacheService : IAppraisalCacheService
{
private readonly IDistributedCache _distributedCache;
private readonly JsonSerializer _serializer;
public AppraisalCacheService(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
_serializer = new JsonSerializer();
}
public async Task<AppraisalResult[]> GetAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
var data = await _distributedCache.GetAsync(key);
if (data != null)
{
using MemoryStream ms = new MemoryStream(data);
using BsonDataReader reader = new BsonDataReader(ms);
var obj = _serializer.Deserialize<AppraisalResultObj>(reader);
return obj.Results;
}
return null;
}
public async Task RemoveAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
await _distributedCache.RemoveAsync(key);
}
public async Task StoreAsync(AppraisalResult[] results, ....)
{
// logic removed for simplicity
var key = GetKey(..);
using MemoryStream ms = new MemoryStream();
using BsonDataWriter writer = new BsonDataWriter(ms);
_serializer.Serialize(writer, new AppraisalResultObj(){
Results = results
});
await _distributedCache.SetAsync(key, ms.ToArray(), new DistributedCacheEntryOptions()
{
SlidingExpiration = TimeSpan.FromDays(7),
AbsoluteExpiration = DateTime.Now.AddDays(30),
});
}
private string GetKey(...)
{
// logic removed for simplicity
return "custom-key....";
}
}
then the code

Json array deserialize from DataContractJsonSerializer method to JsonConvert(newton.json)?

I need to deserialize json array from web api (httpclient). I have DataContractJsonSerializer but no use i need to use JsonConvert, I don't know how to do this. My code:
{
[DataContract]
public class JsonDataContractObject
{
public string ToJson()
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(this.GetType());
Stream s = new MemoryStream();
ser.WriteObject(s, this);
s.Position = 0;
StreamReader sr = new StreamReader(s);
return sr.ReadToEnd();
}
}
}
How to change DataContractJsonSerializer to JsonConvert(newton.json)?.
This is how to quickly serialise an object to json string
JsonConvert.SerializeObject(this);
For more info see https://www.newtonsoft.com/json/help/html/SerializingJSON.htm

UWP Json to C# conversion

I want to serialize some json data I get from the web to classes and use the data, so I went to http://json2csharp.com/ and turned the json as below
json: [{"line_descr":"\u03a0\u0395\u0399\u03a1\u0391\u0399\u0391\u03a3 -
\u0392\u039f\u03a5\u039b\u0391","line_descr_eng":"PEIRAIAS - VOYLA"}]
To this class:
public class RootObject
{
public string line_descr { get; set; }
public string line_descr_eng { get; set; }
}
This is my code:
class LineName
{
public async static Task<RootObject> GetLineName(int linecode)
{
var http = new HttpClient();
var response = await http.GetAsync("http://telematics.oasa.gr/api/?act=getLineName&p1=962");
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
return data;
}
}
[DataContract]
public class RootObject
{
[DataMember]
public string line_descr { get; set; }
[DataMember]
public string line_descr_eng { get; set; }
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
RootObject myLine = await LineName.GetLineName(92);
ResultTextBlock.Text = myLine.line_descr_eng;
}
So when I try to get the data and display it in my textblock I get the error: line_descr_eng is null.
Can someone point where the fault is ? since the line_descr_eng should be
PEIRAIAS - VOYLA but mine is null and after a lot of searching I cant find where the fault is.
Your json is an array, not an object, and you should deserialize it into an array.
public async static Task<RootObject[]> GetLineName(int linecode)
{
var http = new HttpClient();
var response = await http.GetAsync("http://telematics.oasa.gr/api/?act=getLineName&p1=962");
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject[]));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject[])serializer.ReadObject(ms);
return data;
}
//...
var myLines = await LineName.GetLineName(92);
var myLine = myLines.FirstOrDefault();
Also you don't need a memory stream, you can read stream from the http response
var result = await response.Content.ReadAsStreamAsync();
You simple can use the JavaScriptSerializer class instead of DataContractJsonSerializer like this:
Replace:
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
with this:
var ser = new JavaScriptSerializer();
var test = ser.Deserialize<List<RootObject>>(json);
If you cannot find JavaScriptSerializer, then you have to do the simple following steps:
Right click References and do Add Reference, then from Assemblies->Framework select System.Web.Extensions.
Now you should be able to add the following to your class file:
using System.Web.Script.Serialization;
Cited from: https://stackoverflow.com/a/15391388/5056173

Can't access custom class properties when returning object

I have this code which retrieves Json values from a Api link and enters them in a list. In this list there are Ids, all these ids are checked if exist in another API link.
private void button1_Click(object sender, EventArgs e)
{
var spidyApi_searchIdByName_result = api_Handler.GetApi(spidyApi_searchIdByName);
var Gw2Api_isItemIdinListing_result = api_Handler.GetApi(Gw2Api_allListings + spidyApi_searchIdByName_result.???); // can't access object property
}
This is the GetApi method:
public object GetApi(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
try
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
var jsonReader = new JsonTextReader(reader);
var serializer = new JsonSerializer();
return serializer.Deserialize<RootObject>(jsonReader);
}
}
catch (WebException)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<A>("{\"text\":\"no such id\"}");
}
}
This is the RootObject to which the GetApi() method deserializes:
public class RootObject
{
public int id { get; set; }
// ...
}
However, I can't access the returned object's properties when returning an object from GetApi(). How can I access those?
You have two problems.
First, you're returning object from your method, so you can't access any members that object doesn't have. That's why you should return a more specialized type like I already advised, so in this case:
public RootObject GetApi(string url)
{
// ...
return serializer.Deserialize<RootObject>(jsonReader);
}
However, you want this method to be able to do more. You want to return two types from it and also add error handling.
Generics (see T) could help here, where you specifiy the type when calling the method:
public T GetObjectFromApi<T>(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
try
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
var jsonReader = new JsonTextReader(reader);
var serializer = new JsonSerializer();
return serializer.Deserialize<T>(jsonReader);
}
}
catch (WebException)
{
return null;
}
}
Then call it like this:
var spidyApi_searchIdByName_result = api_Handler.GetObjectFromApi<spidyApiResult>(spidyApi_searchIdByName);
if (spidyApi_searchIdByName_result != null)
{
var Gw2Api_isItemIdinListing_result = api_Handler.GetApi<RootObject>(Gw2Api_allListings + spidyApi_searchIdByName_result.someProperty);
}
Of course this swallows the WebException.

invalid JSON generated by default Restsharp JSON serialiser

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.

Categories