HttpClient.GetStringAsync is returning a "Result" object? - c#

I am trying to retrieve a JSON list from my own API with the GetStringAsync method.
when I get it it returns as a "Result" object instead of just a string ?
Then I am trying to Deserialize the JSON array to a list but recieve an error .
This is how the returned string in the DEBUGGER looks from the HttpCLient.GetStringAsync :
"{\"Result\":[{\"id\":92,\"name\":\"Chris Hemsworth\",\"birthDate\":\"1983-8-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":90,\"name\":\"Jennifer Aniston\",\"birthDate\":\"1969-2-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":40,\"name\":\"Edward Norton\",\"birthDate\":\"1969-8-18\",\"role\":\"Writer\",\"originalList\":null}],\"Id\":71,\"Exception\":null,\"Status\":5,\"IsCanceled\":false,\"IsCompleted\":true,\"CreationOptions\":0,\"AsyncState\":null,\"IsFaulted\":false}"
the Exception im getting when trying to convert the JSON object to string:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[BuisnessLogic.Actor]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.To 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<T>) 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.Path 'Result', line 1, position 10.'
UPDATE:
Here is the code:
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}"));
the Actor class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BuisnessLogic
{
public class Actor
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public List<Actor> originalList { get; set; }
public Actor(string name, string birthDate, string role)
{
this.name = name;
this.birthDate = birthDate;
this.role = role;
}
public Actor()
{
}
public override string ToString()
{
return "Person: " + id + "" + name + " " + birthDate + " " + role;
}
}
}
EDIT 2 :
The Controller:
using BuisnessLogic;
using System.Web.Mvc;
namespace WebApplication12.Controllers
{
public class ValuesController : Controller
{
public ILogic _Ilogic;
public ValuesController(ILogic logic)
{
_Ilogic = logic;
}
// GET api/values
public ActionResult GetActors()
{
return Json(_Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
}
}
The data management class :
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Configuration;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Linq;
namespace BuisnessLogic
{
public class Logic : ILogic
{
static string filePath;
private static ConcurrentDictionary<string, Actor> originalList;
const string BACKUP = #"D:\backup.txt";
static Logic()
{
originalList = new ConcurrentDictionary<string, Actor>();
filePath = ConfigurationManager.AppSettings["tempList"];
File.Copy(filePath, BACKUP, true);
SaveOriginal();
}
public async static Task<List<Actor>> GetCelebritiesInner()
{
return originalList.Values.ToList();
}
public async Task<List<Actor>> GetAllActorsAsync()
{
return await GetCelebritiesInner();
}
// Try to read the data from the Json and initialize it. if failed , initialize with whatever it got. return
private static List<Actor> ReadActorsFromJson(string json)
{
List<Actor> celebListReadFromFile;
try
{
var celebJson = File.ReadAllText(json);
celebListReadFromFile = JsonConvert.DeserializeObject<List<Actor>>(celebJson);
}
catch (Exception ex)
{
celebListReadFromFile = new List<Actor>();
// Empty list/whatever it got in it
}
return celebListReadFromFile;
}
public async Task RemoveActorAsync(string name)
{
if (originalList.TryRemove(name, out Actor removedActor))
{
var jsonToWrite = JsonConvert.SerializeObject(await GetCelebritiesInner());
try
{
File.WriteAllText(filePath, jsonToWrite);
}
catch (Exception ex)
{
//Unable to remove due to an error.
}
}
}
public async Task ResetAsync()
{
UpdateFile();
}
//Saving the actor, adding the name as key & object as value.
public static void SaveOriginal()
{
foreach (var currCeleb in ReadActorsFromJson(filePath))
{
originalList.TryAdd(currCeleb.name, currCeleb);
}
}
public static void UpdateFile()
{
File.WriteAllText(filePath, string.Empty);
var text = File.ReadAllText(BACKUP);
File.WriteAllText(filePath, text);
}
}
}
The update method that goes to the uri and gets the string :
public async void update()
{
var b = await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}");
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(b);
foreach (Actor actor in celebrities)
{
actorBindingSource.Add(actor);
}
}

The JSON shown in your question is a serialised instance of Task<T>, which includes properties such as Result, AsyncState and IsFaulted. It's clear that this should be a serialised instance of T (List<Actor> in your case), which usually means there's a missing await somewhere.
This "missing await" is in your ValuesController.GetActors, which is passing the result of ILogic.GetAllActorsAsync into Json. This ends up with an instance of Task<List<Actor>> being passed in, instead of just List<Actor>. In order to resolve that, use await, like this:
public async Task<ActionResult> GetActors()
{
return Json(await _Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
This also requires making GetActors async, as I've shown above.

First replace **Result** with Result.
var stringResult = await HttpCLient.GetStringAsync().Replace("**Result**", "Result");
Second create the classes which has the same properties as the json result.
public class JsonResult
{
public List<ResultObject> Result { get; set; }
public int Id { get; set; }
public string Exception { get; set; }
public int Status { get; set; }
public bool IsCanceled { get; set; }
public bool IsComplete { get; set; }
public int CreationOptions { get; set; }
public string AsyncState { get; set; }
public bool IsFaulted { get; set; }
}
public class ResultObject
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public string originalList { get; set; }
}
And than deserialize the string with:
var resultObject = JsonConvert.DeserializeObject<JsonResult>(result);
And resultObject will contain the whole result.

Related

class property manipulation when parsing json data in c#

I am practicing with web api. My goal is to create a Get endpoint, which receive data from an external api, then return a different result. external api link: https://www.themealdb.com/api/json/v1/1/search.php?f=a, The external api data looks like:
{
"meals": [
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"strDrinkAlternate": null,
"strCategory": "Dessert",
.....
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
....
}
]
}
I want my endpoint provide a different result like the following:
[
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"ingredients": ["Apple", "sugar"...]
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
"ingredients": ["Apple", "sugar"...]
}
]
The following code is what I attempted so far, It's working, but the moment I changed property ingredient1 from public to private, that ingredient in list will become null, also, there are so many ingredients, some of them are null by default, I don't want to add them if they are null, how can I fix these two issues? Thanks a lot
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;
using RestSharp;
namespace testAPI.Controllers;
public class Content
{
[JsonPropertyName("meals")]
public List<Meal> Meals { get; set; }
}
public class Meal
{
[JsonPropertyName("idMeal")]
public string MealId { get; set; }
[JsonPropertyName("strMeal")]
public string Name { get; set; }
[JsonPropertyName("strIngredient1")]
public string Ingredient1 { get; set; }
[JsonPropertyName("strIngredient2")]
public string Ingredient2 { get; set; }
[JsonPropertyName("strIngredient20")]
public string Ingredient20 { get; set; }
public List<string> Ingredients
{
get { return new List<string>(){Ingredient1, Ingredient2, Ingredient20};}
}
}
[ApiController]
[Route("api/[controller]")]
public class DishesController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
var mealList = JsonSerializer.Deserialize<Content>(response.Content);
return Ok(mealList.Meals);
}
}
To address the problems one at a time...
the moment I changed property ingredient1 from public to private, that ingredient in list will become null
Changing the access modifier affects both deserialization and serialization, so this cannot be used to only stop it from serializing the property. You should split the data models up into what you want to receive and what you want to expose/return.
there are so many ingredients, some of them are null by default, I don't want to add them if they are null
Addition to splitting up the data models you can handle this when mapping from one model to the other.
The following code should fix both issues:
namespace TheMealDb.Models
{
// These are the models you receive from TheMealDb
// JSON converted to classes with https://json2csharp.com/
public class Root
{
public List<Meal> meals { get; set; }
}
public class Meal
{
public string idMeal { get; set; }
public string strMeal { get; set; }
public string strIngredient1 { get; set; }
public string strIngredient2 { get; set; }
public string strIngredient3 { get; set; }
// Other properties removed for brevity...
}
}
namespace Internal.Models
{
// This is the model you want to return from your controller action
public class Meal
{
[JsonPropertyName("id")] // No need to use the same name as from themealdb
public string Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("ingredients")]
public List<string> Ingredients { get; set; }
}
}
Now, to fetch, map and return the data in your controller action:
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
// Deserialize to the "TheMealDb" models
var mealList = JsonSerializer.Deserialize<TheMealDb.Models.Root>(response.Content);
// Map to your own models
var myMealList = mealDbList.meals?.Select(MapToInternal);
return Ok(myMealList);
}
// Map "TheMealDb" model to your own model
private Internal.Models.Meal MapToInternal(TheMealDb.Models.Meal externalMeal)
{
return new Internal.Models.Meal
{
Id = externalMeal.idMeal,
Name = externalMeal.strMeal,
Ingredients = new []
{
externalMeal.strIngredient1,
externalMeal.strIngredient2,
externalMeal.strIngredient3,
// ...
}
// Remove empty/null ingredients
.Where(ingr => !string.IsNullOrEmpty(ingr))
.ToList()
};
}
See the code in action.

Newtonsoft.Json parsing json from webpage doesn't work

I've made a simple program that gets json from a website. It should give out some of the json attributes, but it doesn't do it. It simply gives me a clear String without text in it. Can someone help me?
My Code:
using System;
using System.Linq;
using System.Diagnostics;
using System.Threading;
using System.Net;
using System.IO;
using Newtonsoft.Json;
namespace ESEL_Scraper_2._0
{
class MyJsonType
{
public string title { get; set; }
public int id { get; set; }
}
class Program
{
static void Main(string[] args)
{
WebClient client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
string site = client.DownloadString($"https://esel.at/api/termine/data?date=05.09.2020&selection=false");
var myJsonObject = JsonConvert.DeserializeObject<MyJsonType>(site);
Console.WriteLine(myJsonObject.title);
}
}
}
The JSON: https://esel.at/api/termine/data?date=05.09.2020&selection=false
MyJsonType expects the body to be like,
{
"id": 1,
"title": "title"
}
but in your case, the json is,
{
"termine": [
{ -> object }
{ -> object }
]
}
You have an array of Objects that fit into your MyJsonType. Use the following class to deserialize to
public class RootObject
{
[JsonProperty("termine")] // the name of the property is case sensetive.
public List<MyJsonType> Termine {get;set;}
}
public class MyJsonType
{
[JsonProperty("title")]
public string Title { get; set; } //C# uses uppercase first letter for properties.
[JsonProperty("id")]
public int Id { get; set; }
}
// in your main,
var obj = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(obj.Termine.First().Title);
You need to structure your call as per your json string.
You class should look like this
public class ParentJsonType
{
public List<MyJsonType> termine { get; set; }
}
public class MyJsonType
{
public string title { get; set; }
public int id { get; set; }
}
and in your code you can deserialize
WebClient client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
string site = client.DownloadString($"https://esel.at/api/termine/data?date=05.09.2020&selection=false");
var myJsonObject = JsonConvert.DeserializeObject<List<MyJsonType>>(site);
foreach(var myJosnType in myJsonObject)
{
//add your logic here
Console.WriteLine(myJosnType.title);
}
Yes, guys that already answered are absolutely right.
The point is in the wrong model you have, which has no necessary structure to contain a responded context.
The following approach is also working. The correct model for that JSON should be:
public class Termine
{
public Int64 id {get;set;}//":106102,
public String title {get;set;}//":"curated by 2020",
public String category {get;set;}//":"eSeLs Neugierde",
public String startdate {get;set;}//":"Sa, 05.09.2020",
public String startdatetime {get;set;}//":"Sa, 05.09. 11:00",
public String starttime {get;set;}//":"11:00",
public String enddate {get;set;}//":"Sa, 05.09.2020",
public List<object> runtime {get;set;}//":[ 0, "nur noch heute" ],
public String thumbnail {get;set;}//":"https:\/\/static.esel.at\/mini\/\/upload\/IpeP5wgYL7sRucTuFtpJg53zgG7hby5IiXv5txLk.jpeg",
public String thumbnail_credits {get;set;}//":null,
public String type {get;set;}//":"upcoming",
public String recommended {get;set;}//":"(Wie) Schafft's Kunst als Aktivismus in Galerier\u00e4ume?`",
public Boolean online_event {get;set;}//":false,
public String feed_urls {get;set;}//":null,
public String status {get;set;}//":"",
public String tags {get;set;}//":"Galerienfestival, internationale KuratorInnen, Aktivismus, Kunst, curatedby",
public String url {get;set;}//":"https:\/\/esel.at\/termin\/106102\/curated-by-2020",
public DateTime sort_date {get;set;}//":"2020-09-05 11:00:00",
public String sort_category {get;set;}//":"eselsneugierde",
public String location_url {get;set;}//":"https:\/\/esel.at\/location\/933\/wien",
public String location {get;set;}//":"Wien"
public override String ToString(){
return String.Format("[{0}] {1} ({2})", this.id, this.title, this.location_url);
}
}
public class Meta
{
public List<String> next {get;set;}//":[ "Sonntag,<br><nobr>06. September 2020<\/nobr>", "06.09.2020", "06092020" ],
public DateTime now {get;set;}//":"2020-09-05T18:52:05.000040Z",
public List<String> da {get;set;}//":[ "Samstag,<br><nobr>05. September 2020<\/nobr>", "05.09.2020", "05092020" ],
public DateTime end {get;set;}//":"2020-09-05T21:59:59.999999Z",
public DateTime runtime {get;set;}//":"2020-09-04T22:00:00.000000Z",
public Int32 upcoming {get;set;}//":14
public Int32 running {get;set;}//":87,
public Int64 termine {get;set;}//":16
}
public class Context
{
public List<Termine> termine{get;set;}
public Meta meta {get;set;}
}
So, your code will work with a few changes:
public static void Main(string[] args)
{
WebClient client = new WebClient()
{
Encoding = System.Text.Encoding.UTF8
};
string site = client.DownloadString("https://esel.at/api/termine/data?date=05.09.2020&selection=false");
Context ctx = JsonConvert.DeserializeObject<Context>(site);
ctx.termine.ForEach(Console.WriteLine);
}
Here is the link to the full solution where you can run and test.
https://dotnetfiddle.net/elq5Lv

Json Deserializer in C# is returning Incorrect Values from Json Request Response

I am attempting to return the Json response deserialized from the following https://www.supremenewyork.com/mobile_stock.json
Below is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Text;
using System.Drawing;
using System.IO;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using RestSharp;
using System.Threading.Tasks;
using System.Globalization;
namespace SupremeMobileMonitor
{
class Program
{
static async Task Main(string[] args)
{
var program = new Program();
await program.GetItem();
}
// Declaring variables in the list
static List<ItemDetail> ProductList = new List<ItemDetail>();
List<string> productDesc = new List<string> { "new_item", "price", "category", "imageurl", "itemURL" };
List<string> category = new List<string> { "jackets", "shirts", "tops_sweaters", "pants", "hats", "accessories", "shoes", "skate" };
//creating a class for intializing Json Deserializer
public class MobileStockResponse
{
[JsonProperty("unique_image_url_prefixes")]
public List<object> UniqueImageUrlPrefixes { get; set; }
[JsonProperty("products_and_categories")]
public Dictionary<string, List<ProductsAndCategory>> ProductsAndCategories { get; set; }
[JsonProperty("release_date")]
public string ReleaseDate { get; set; }
[JsonProperty("release_week")]
public string ReleaseWeek { get; set; }
}
public partial class ProductsAndCategory
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("image_url")]
public string ImageUrl { get; set; }
[JsonProperty("image_url_hi")]
public string ImageUrlHi { get; set; }
[JsonProperty("price")]
public long Price { get; set; }
[JsonProperty("sale_price")]
public long SalePrice { get; set; }
[JsonProperty("new_item")]
public bool NewItem { get; set; }
[JsonProperty("position")]
public long Position { get; set; }
[JsonProperty("category_name")]
public string CategoryName { get; set; }
}
//Initializing HttpClient for Requests and po
public async Task GetItem()
{
var client = new HttpClient();
var request = new HttpRequestMessage
{
RequestUri = new Uri("https://www.supremenewyork.com/mobile_stock.json"),
Method = HttpMethod.Get
};
var response = await client.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
var responseObject = JsonConvert.DeserializeObject<ProductsAndCategory>(responseContent);
Console.WriteLine(responseObject);
}
}
}
When I try to return a value (example: responseObject.id) It will just return '0'
When I try to return the complete response, it returns "SupremeMobileMonitor.Program+ProductsAndCategory"
Any idea why I can't get it returned and what I'm messing up my deserialization? Unfortunately the category known as "new" on the endpoint interferes with the C# keywords therefore removing my option to use dynamic deserialization.
jslowik has the correct answer for your question, how to deserialize it.
To Print the object, you can either create an override ToString() method and print out only the things you are interested in, or you can print the object by serializing it to a string.
Console.WriteLine(JsonConvert.SerializeObject(productsAndCategories, Formatting.Indented);
This will give you a json representation again of the object and show you all the values.
SideNote: If you want to get specific items from, Say, Bags, you can use Linq to get it...
Console.WriteLine(JsonConvert.SerializeObject(responseObject.ProductsAndCategories["Bags"].Select(x => x.Id)));
// Output:
[173389,172978,173019,172974,173018,173001]
Off hand I would just deserialize the full object. Example:
// Full model represented by your class
var responseObject = JsonConvert.DeserializeObject<MobileStockResponse>(responseContent);
// The products and categories dictionaries you're looking for
var productsAndCategories = responseObject.ProductsAndCategories;

Azure Service-Fabric and DocumentDB message serialization issue

So, - in my DocumentDB I may have the following document:
{
"id": 1,
"type": "A",
"content": {
"x": 1,
"y": 2
}
}
That may be backed by this model:
public class acontent
{
public int x { get; set; }
public int y { get; set; }
}
public class document
{
public int id { get; set; }
public string type { get; set; }
public object content { get; set; }
}
public class documenta : document
{
public new acontent content { get; set; }
}
The idea here is that document is a complex object where content may vary depending on type.
Now, - in my ServiceFabric application I have a stateless microservice that reads from DocumentDB and should return a document type object when called from the ServiceProxy.
The problem in this is that the DocumentQuery from the DocumentDB SDK, uses Json.NET serializer when querying the database, whilst servicefabric uses DataContractSerializer for serializing the service-messages.
So when the content part of document class is being deserialized from the DocumentDB it becomes:
Newtonsoft.Json.Linq.JObject
But when it is serialized back through the returned service-message you get the exception:
Type 'Newtonsoft.Json.Linq.JToken' is a recursive collection data
contract which is not supported. Consider modifying the definition of
collection 'Newtonsoft.Json.Linq.JToken' to remove references to
itself.
To illustrate this issue try the folowing code:
using System;
using System.IO;
using System.Text;
using System.Runtime.Serialization.Json;
using Newtonsoft.Json;
namespace jsoinissue
{
public class acontent
{
public int x { get; set; }
public int y { get; set; }
}
public class document
{
public int id { get; set; }
public string type { get; set; }
public object content { get; set; }
}
public class documenta : document
{
public new acontent content { get; set; }
}
public class Program
{
private const string JSON_A = "{\"id\":1,\"type\":\"A\",\"content\":{\"x\":1,\"y\":2}}";
private static string SerializeObject<T> (T obj)
{
try
{
DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T));
using (var ms = new MemoryStream())
{
js.WriteObject(ms, obj);
ms.Position = 0;
using (var sr = new StreamReader(ms))
return sr.ReadToEnd();
}
}
catch (Exception e)
{
return String.Format("EXCEPTION: {0}",e.Message);
}
}
public static void Main()
{
var A = JsonConvert.DeserializeObject<document>(JSON_A);
var a = SerializeObject<document>(A);//HERE BE TROUBLE
Console.WriteLine(a);
Console.ReadKey();
}
}
}
How could I best resolve this issue?
Your basic problem is that DataContractJsonSerializer does not support untyped, free-form JSON data. As explained in Working with untyped JSON in a WCF service the System.Json namespace was added to Silverlight for this purpose, but it seems that it never made it into the full .Net class library.
Instead, in your stateless microservice can do a nested serialization where the free-form JSON is represented as an escaped string literal when serializing using the data contract serializer. Thus your classes would look something like this:
[DataContract]
[JsonObject]
public abstract class documentbase
{
[DataMember]
[JsonProperty]
public int id { get; set; }
[DataMember]
[JsonProperty]
public string type { get; set; }
[IgnoreDataMember]
[JsonProperty("content")]
public abstract JToken JsonContent { get; set; }
[JsonIgnore]
[DataMember(Name = "content")]
string DataContractContent
{
get
{
if (JsonContent == null)
return null;
return JsonContent.ToString(Newtonsoft.Json.Formatting.None);
}
set
{
if (string.IsNullOrEmpty(value))
JsonContent = null;
else
JsonContent = JToken.Parse(value);
}
}
}
[DataContract]
[JsonObject]
public class document : documentbase
{
JToken content;
public override JToken JsonContent { get { return content; } set { content = value; } }
}
[DataContract]
[JsonObject]
public class document<T> : documentbase where T : class
{
[IgnoreDataMember]
[JsonIgnore]
public T Content { get; set; }
public override JToken JsonContent
{
get
{
if (Content == null)
return null;
return JToken.FromObject(Content);
}
set
{
if (value == null || value.Type == JTokenType.Null)
Content = null;
else
Content = value.ToObject<T>();
}
}
}
Then the JSON generated by SerializeObject<document>(A) will look like:
{
"content":"{\"x\":1,\"y\":2}",
"id":1,
"type":"A"
}
Then, on the receiving system, you can deserialize to a document using the data contract serializer, then query the deserialized JToken JsonContent with LINQ to JSON. Alternatively, if the receiving system knows to expect a document<acontent> it can deserialize the data contract JSON as such, since document and document<T> have identical data contracts.
Have you looked into changing away from DataContractSerializer to a serializer with better support instead? Here's how you'd plug in a different serializer.
class InitializationCallbackAdapter
{
public Task OnInitialize()
{
this.StateManager.TryAddStateSerializer(new MyStateSerializer());
return Task.FromResult(true);
}
public IReliableStateManager StateManager { get; set; }
}
class MyStatefulService : StatefulService
{
public MyStatefulService(StatefulServiceContext context)
: this(context, new InitializationCallbackAdapter())
{
}
public MyStatefulService(StatefulServiceContext context, InitializationCallbackAdapter adapter)
: base(context, new ReliableStateManager(context, new ReliableStateManagerConfiguration(onInitializeStateSerializersEvent: adapter.OnInitialize)))
{
adapter.StateManager = this.StateManager;
}
}
This could be newtonsoft or whatever. Also I believe that the method is currently marked "Deprecated" however there's no alternative, so if it solves your problem go ahead and use it.

Derserialize JSON Object from Firebase in C#

I am querying Firebase and retrieve a collection of objects like so:
{"-K5f0ccEKkVkxTAavQKY": {
"Appeal": {
"ID": "1450273330435",
"comps": [
162248,
162272,
162273,
162281,
162544
],
"property": {
"Address": "15 Main Street",
"propID": 169729
},
"timeDateStamp": "Wed Dec 16 2015 08:42:10 GMT-0500 (Eastern Standard Time)",
"userUUID": "google:229139952703238437512",
"year": 2016
}
}}
I would like to deserialize them into objects with this definition:
public class Appeal
{
public string ID;
public List<string> comps;
public AppealProperty property;
public string timeDateStamp;
public string UUID;
public int year;
}
public class AppealProperty
{
public string address;
public string propID;
}
I have troubles getting it deserialized. I don't need the initial string (e.g. "K5f0ccEKkVkxTAavQKY"). I'm able to change the object definitions if need be. I have a feeling a Dictionary would be useful.
The quick and dirty object is to use Dictionary<string,Appeal> as your deserialization target. At that point it would be as simple as:
var firebaseLookup = JsonConvert.DeserializeObject<Dictionary<string,Appeal>>(json);
var data = firebaseLookup.Values.ToList(); // or FirstOrDefault();
This approach would also handle the case if you ever had to get multiple objects at once, and it would give you the opportunity to use that key if it turns out the key was important after all.
You could serialise your data into the classes below.
public class AppealProperty
{
public string Address { get; set; }
public int propID { get; set; }
}
public class Appeal
{
public string ID { get; set; }
public List<int> comps { get; set; }
public AppealProperty property { get; set; }
public string timeDateStamp { get; set; }
public string userUUID { get; set; }
public int year { get; set; }
}
public class FireBase
{
public Appeal Appeal { get; set; }
}
public class RootObject
{
[JsonProperty(PropertyName = " - K5f0ccEKkVkxTAavQKY")]
public FireBase FireBaseRoot
{
get;
set;
}
}
Assuming that you are using JSON.NET, you can then get the object you are after, using this snippet:
var firebaseObject = JsonConvert.DeserializeObject<RootObject>(json);
var data = firebaseObject.FireBaseRoot.Appeal;
If the root name is dynamic, as indicated by your comment, you could skip the root instead and serialise straight into the FireBase class:
JObject parsedJson = JObject.Parse(json);
var fireBase = parsedJson.First.Children().First().ToObject(typeof (FireBase));
Since I've never been able to parse a DataSnapshot with newtonSoft Json parser, I did this to build a list of object I needed to put in a ListView:
MyModelObject class
public class MyModelObject: Java.Lang.Object
{
public string Title { get; set; }
public string Description { get; set; }
public MyModelObject(){}
}
into My Listener
public void OnDataChange(DataSnapshot snapshot)
{
List<MyModelObjecct> myList = new List<MyModelObject>();
myList = databaseService
.GetMyModelObjectList(snapshot
.Children?
.ToEnumerable<DataSnapshot>());
}
Method into the DatabaseService class
public List<MyModelObject> GetMyModelObjectList(IEnumerable<DataSnapshot> enumerableSnapshot)
{
List<MyModelObject> list = new List<MyModelObject>();
foreach (var item in enumerableSnapshot)
{
list.Add(ObjectExtensions.DataSnapshotToObject<MyModelObject>(item.Children?.ToEnumerable<DataSnapshot>()));
}
return list;
}
ObjectExtensions class
public static class ObjectExtensions
{
public static T DataSnapshotToObject<T>(IEnumerable<DataSnapshot> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
someObjectType
.GetProperty(item.Key)
.SetValue(someObject, item.Value.ToString(), null);
}
return someObject;
}
}

Categories

Resources