webapi $type customization - asp.net-web-api

I have a web api written in aspnet webapi. The main idea is to work with inherirance. What you see here is a test project to play arround before adding this to the real project. To do that on the webconfig file i have added:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
Here is the model
public abstract class Person
{
public string Name { get; set; }
public string DocumentNumber { get; set; }
}
public class Teacher : Person
{
public string School { get; set; }
}
public class Employee : Person
{
public string PersonnelNumber { get; set; }
}
As a result, here is a response from the server:
[
{
"$type": "JsonConverterTest.Models.Employee, JsonConverterTest",
"PersonnelNumber": "1001",
"Name": "Emp1",
"DocumentNumber": "01"
},
{
"$type": "JsonConverterTest.Models.Employee, JsonConverterTest",
"PersonnelNumber": "1002",
"Name": "Emp2",
"DocumentNumber": "02"
},
{
"$type": "JsonConverterTest.Models.Teacher, JsonConverterTest",
"Name": "Teacher1",
"DocumentNumber": "10"
}
]
I need $type for web api deserization process to create the right instance for person.
What can i do to change the $type value to a more simple one like: "Models.Employee" or "Models.Teacher" and get rid of the assembly name?
Thanks in advance.

Related

.NET Core : deserialization issue + how to get better insight into non-useful error text

I have the following JSON which I ran through a validator and 'Pasted JSON as classes' to build a model from the schema in Visual Studio:
{
"entity": {
"Successful Requests": [
{
"Status": 201,
"Resource ID": 34715818,
"Message": "Created resource 1 at URI: /rest/equipment/ids/34715818"
},
{
"Status": 201,
"Resource ID": 34715838,
"Message": "Created resource 2 at URI: /rest/equipment/ids/34715838"
}
],
"Failed Requests": [
{
"Status": 500,
"Resource ID": -1,
"Message": "Failed to create new resource 1. Bulk update failed. Cause: Template 'xxx' not found."
},
{
"Status": 500,
"Resource ID": -1,
"Message": "Failed to create new resource 2. Bulk update failed. Cause: Template 'xxx' not found."
}
]
},
"variant": {
"language": null,
"mediaType": {
"type": "application",
"subtype": "json",
"parameters": {},
"wildcardType": false,
"wildcardSubtype": false
},
"encoding": null,
"languageString": null
},
"annotations": [],
"mediaType": {
"type": "application",
"subtype": "json",
"parameters": {},
"wildcardType": false,
"wildcardSubtype": false
},
"language": null,
"encoding": null
}
This builds the following classes (I added the JsonProperties in the entity class because the property names contain spaces, I also tried without them and I get the same error):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace xxx.Data.Models
{
public class Rootobject
{
public Entity entity { get; set; }
public Variant variant { get; set; }
public object[] annotations { get; set; }
public Mediatype1 mediaType { get; set; }
public object language { get; set; }
public object encoding { get; set; }
}
public class Entity
{
[JsonProperty("Successful Requests")]
public SuccessfulRequest[] SuccessfulRequests { get; set; }
[JsonProperty("Failed Requests")]
public FailedRequest[] FailedRequests { get; set; }
}
public class SuccessfulRequest
{
public int Status { get; set; }
public int ResourceID { get; set; }
public string Message { get; set; }
}
public class FailedRequest
{
public int Status { get; set; }
public int ResourceID { get; set; }
public string Message { get; set; }
}
public class Variant
{
public object language { get; set; }
public Mediatype mediaType { get; set; }
public object encoding { get; set; }
public object languageString { get; set; }
}
public class Mediatype
{
public string type { get; set; }
public string subtype { get; set; }
public Parameters parameters { get; set; }
public bool wildcardType { get; set; }
public bool wildcardSubtype { get; set; }
}
public class Parameters
{
}
public class Mediatype1
{
public string type { get; set; }
public string subtype { get; set; }
public Parameters1 parameters { get; set; }
public bool wildcardType { get; set; }
public bool wildcardSubtype { get; set; }
}
public class Parameters1
{
}
}
I make an API call in code:
var response = await _repositorySvc.PutBulkEquipment(requestBody, Guid.NewGuid());
var result = response.Content.ReadAsStringAsync().Result;
_logger.LogWarning("------------------Result:");
_logger.LogWarning(result);
Which returns the following JSON string in the console:
{
"entity": "{\"Successful Requests\":[{\"Status\":201,\"Resource ID\":34715872,\"Message\":\"Created resource 1 at URI: /rest/equipment/ids/34715872\"},{\"Status\":201,\"Resource ID\":34715892,\"Message\":\"Created resource 2 at URI: /rest/equipment/ids/34715892\"}],\"Failed Requests\":[]}",
"variant": {
"language": null,
"mediaType": {
"type": "application",
"subtype": "json",
"parameters": {},
"wildcardType": false,
"wildcardSubtype": false
},
"encoding": null,
"languageString": null
},
"annotations": [],
"mediaType": {
"type": "application",
"subtype": "json",
"parameters": {},
"wildcardType": false,
"wildcardSubtype": false
},
"language": null,
"encoding": null
}
Then, when I attempt to deserialize the string to the Entity class:
var deserializedResponse = JsonConvert.DeserializeObject<Rootobject>(result);
I get the following error:
Error converting value
"{"Successful Requests":[{"Status":201,"Resource ID":34715872,"Message":"Created resource 1 at URI: /rest/equipment/ids/34715872"},{"Status":201,"Resource ID":34715892,"Message":"Created resource 2 at URI: /rest/equipment/ids/34715892"}],"Failed Requests":[]}"
to type 'xxx.Data.Models.Entity'.
Path 'entity', line 1, position 290.
Would anyone be able to spot any mistakes I'm making that I might be missing in the above scenario that could be contributing to me banging my head on a wall for the past day and a half on this? Everything looks correct to me and I'm stumped - I do a lot of deserialization and usually it's ez-mode so I'm not sure what I'm missing.
Is there any way to get better insight into deserialization issues in .NET Core?
Thank you!
If this is the JSON response:
"entity": "{\"Successful Requests\":[...],\"Failed Requests\":[]}",
then entity is of type string. Note the quotes in the beginning and the end. Also note that all the inner quotes are escaped using backslashes.
And the error message says exactly that, it cannot convert that string into an object. it did expect something more like
"entity": {"Successful Requests":[...], "Failed Requests":[]},

GraphQL dotnet Client response not deserializing

When deserializing into a dynamic I can get a response but when I try to deserialize into a typed object I get nothing back.
Types being serialized
public class User {
public string Forename { get; set; }
}
public class UserCollectionResponseType {
public List<User> Items { get; set; }
}
Request being made:
var response = await graphQLHttpClient.SendQueryAsync<UserCollectionResponseType >(this.request).ConfigureAwait(false);
Sample response from API
{
"data": {
"users": {
"items": [
{
"forename": "4212hotp0i"
},
{
"forename": "XO - Test"
},
{
"forename": "5422q5htsd"
},
{
"forename": "XR - Test"
},
{
"forename": "2035snyyex"
},
{
"forename": "2379plsmri"
},
{
"forename": "7100e1igjl"
},
{
"forename": "94 - Test"
},
{
"forename": "ZX - Test"
},
{
"forename": "Test"
}
]
}
}
}
I was missing the Data part of the Json when trying to deserialize into an object.
My final objects looked like this:
public partial class Data {
[JsonProperty("users")]
public Users Users { get; set; }
}
public partial class Users {
[JsonProperty("items")]
public Item[] Items { get; set; }
}
public partial class Item {
[JsonProperty("forename")]
public string Forename { get; set; }
}

C# parse JSON to listview?

Ho can deserialize this json to listview of xamarin
I try to make a simple deserilize but nohing
{
"1": {
"Category": "IT",
"DateB": "Mon, 20 May 2019 00:00:00 GMT",
"Description": "asdads",
"ProductName": "test2",
"Price": 123,
"ProductD": false,
"id": 1
},
"2": {
"Category": "Shop",
"DateB": "Mon, 20 May 2019 00:00:00 GMT",
"Description": "asdads",
"ProductName": "test123132",
"Price": 123,
"ProductD": false,
"id": 2
}
}
You can convert JSON to C# model using quicktype :
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Product
{
[JsonProperty("Category")]
public string Category { get; set; }
[JsonProperty("DateB")]
public string DateB { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
[JsonProperty("ProductName")]
public string ProductName { get; set; }
[JsonProperty("Price")]
public long Price { get; set; }
[JsonProperty("ProductD")]
public bool ProductD { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
}
public partial class Product
{
public static Dictionary<string, Product> FromJson(string json) => JsonConvert.DeserializeObject<Dictionary<string, Product>>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Dictionary<string, Product> self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
}
And after create ListView with ViewCell and ViewModel. In this case, ViewModel will include properties from the product model.

Rasa NLU:Entity Synonyms detection inconsistency

Me and my team have been using Rasa NLU as a replacement for MS LUIS for over 2 months now, and it has worked out pretty well for us so far. Now we have around 900 entries as Entity Synonyms(as we were using List entity in LUIS).
And only for some utterances, the entity is detected as synonyms and for the majority of utterances, it is unable to detect Entity Synonyms. In order to detect synonyms, I have to create another simple entity which again we are manually training with all the synonym values, once the intents are trained with this simple Entity Rasa seems to detect entity for this intent as both simple and synonyms.
And another quick question, Is the Entity Synonyms in Rasa designed to return only one matched entity(unlike LUIS which used to return all the matched entities values)?
Is there any alternative to list entity from LUIS here in Rasa?
Entity Synonyms in Rasa can lead to some confusion. The actual functionality that they provide is very simple. For each entity that is parsed by the model the value of that entity is checked against the list of entity synonyms. If the value matches an entity synonym then it is replaced with the synonym value.
The big catch in the above statement is that the the entity has to be identified by the model before it can be replaced with a synonym.
So take this as a simplified example. Here is my entity synonym definition:
{
"value": "New York City",
"synonyms": ["NYC", "nyc", "the big apple"]
}
If my training data only provides this example:
{
"text": "in the center of NYC",
"intent": "search",
"entities": [
{
"start": 17,
"end": 20,
"value": "New York City",
"entity": "city"
}
]
}
It is very unlikely that my model will be able to detect an entity in a sentence like In the center of the big apple. As I said above if the big apple isn't parsed as an entity by the model it cannot be replaced by the entity synonyms to read New York City.
For this reason you should include more examples in the actual common_examples of the training data with the entities labeled. Once all of the variations of the entity are being classified correctly then add those values to the entity synonym and they will be replaced.
[
{
"text": "in the center of NYC",
"intent": "search",
"entities": [
{
"start": 17,
"end": 20,
"value": "New York City",
"entity": "city"
}
]
},
{
"text": "in the centre of New York City",
"intent": "search",
"entities": [
{
"start": 17,
"end": 30,
"value": "New York City",
"entity": "city"
}
]
}
]
I've opened a pull request into the Rasa docs page to add a note to this effect.
Firstly, I have downloaded some LUIS model JSON for doing this, as shown in the following screenshot:
Next, I have written a sample C# console app for converting LUIS Model Schema into RASA.
Here is the LUISModel model class.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace JSONConversion.Models
{
public class LuisSchema
{
public string luis_schema_version { get; set; }
public string versionId { get; set; }
public string name { get; set; }
public string desc { get; set; }
public string culture { get; set; }
public List<Intent> intents { get; set; }
public List<entity> entities { get; set; }
public object[] composites { get; set; }
public List<Closedlist> closedLists { get; set; }
public List<string> bing_entities { get; set; }
public object[] actions { get; set; }
public List<Model_Features> model_features { get; set; }
public List<regex_Features> regex_features { get; set; }
public List<Utterance> utterances { get; set; }
}
public class regex_Features
{
public string name { get; set; }
public string pattern { get; set; }
public bool activated { get; set; }
}
public class Intent
{
public string name { get; set; }
}
public class entity
{
public string name { get; set; }
}
public class Closedlist
{
public string name { get; set; }
public List<Sublist> subLists { get; set; }
}
public class Sublist
{
public string canonicalForm { get; set; }
public List<string> list { get; set; }
}
public class Model_Features
{
public string name { get; set; }
public bool mode { get; set; }
public string words { get; set; }
public bool activated { get; set; }
}
public class Utterance
{
public string text { get; set; }
public string intent { get; set; }
[JsonProperty("entities")]
public List<Entities> Entities { get; set; }
}
public class Entities
{
[JsonProperty("entity")]
public string Entity { get; set; }
public int startPos { get; set; }
public int endPos { get; set; }
}
}
Here is the RASAModel model class:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace JSONConversion.Models
{
public class RASASchema
{
public Rasa_Nlu_Data rasa_nlu_data { get; set; }
}
public class Rasa_Nlu_Data
{
public List<Entity_Synonyms> entity_synonyms { get; set; }
public List<Regex_Features> regex_features { get; set; }
public List<Common_Examples> common_examples { get; set; }
}
public class Entity_Synonyms
{
public string value { get; set; }
public List<string> synonyms { get; set; }
}
public class Common_Examples
{
public string text { get; set; }
public string intent { get; set; }
public List<Entity> entities { get; set; }
}
public class Entity
{
public string entity { get; set; }
public string value { get; set; }
public int start { get; set; }
public int end { get; set; }
}
public class Regex_Features
{
public string name { get; set; }
public string pattern { get; set; }
}
}
And I have written 2 methods which parse the LUISModel model class for synonyms from the phraselist section and adds them in the common_examples object in RASA_NLU training object.
using JSONConversion.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace JSONConversion.Services
{
public static class JSONHelper
{
public static Task<string> ReadFromFile(string FilePath)
{
try
{
Task<string> readFromFileTask = Task.Run<string>(() =>
{
return File.ReadAllText(FilePath);
});
return readFromFileTask;
}
catch(Exception ex)
{
throw;
}
}
public static RASASchema ConvertLUISJSON(string StringifiedLUISJson)
{
try
{
LuisSchema luisSchema = JsonConvert.DeserializeObject<LuisSchema>(StringifiedLUISJson);
RASASchema rasaSchema = new RASASchema();
rasaSchema.rasa_nlu_data = new Rasa_Nlu_Data();
rasaSchema.rasa_nlu_data.common_examples = new List<Common_Examples>();
rasaSchema.rasa_nlu_data.entity_synonyms = new List<Entity_Synonyms>();
rasaSchema.rasa_nlu_data.regex_features = new List<Regex_Features>();
luisSchema.closedLists.ForEach(x =>
{
x.subLists.ForEach(y =>
{
rasaSchema.rasa_nlu_data.entity_synonyms.Add(new Entity_Synonyms()
{
value = y.canonicalForm,
synonyms = y.list
});
});
});
luisSchema.model_features.ForEach(x =>
{
rasaSchema.rasa_nlu_data.entity_synonyms.Add(new Entity_Synonyms()
{
value = x.name,
synonyms = x.words.Split(',').ToList()
});
});
luisSchema.regex_features.ForEach(x =>
{
rasaSchema.rasa_nlu_data.regex_features.Add(new Regex_Features()
{
name = x.name,
pattern = x.pattern
});
});
luisSchema.utterances.ForEach(x =>
{
Common_Examples rasaUtterances = new Common_Examples();
rasaUtterances.text = x.text;
rasaUtterances.intent = x.intent;
List<Entity> listOfRASAEntity = new List<Entity>();
x.Entities.ForEach(y =>
{
listOfRASAEntity.Add(new Entity()
{
start = y.startPos,
end = y.endPos,
entity = y.Entity,
value = x.text.Substring(y.startPos, (y.endPos - y.startPos) + 1)
});
});
rasaUtterances.entities = listOfRASAEntity;
rasaSchema.rasa_nlu_data.common_examples.Add(rasaUtterances);
});
return rasaSchema;
}
catch (Exception ex)
{
throw;
}
}
}
}
And just called those JSON conversion methods to convert LUIS Models into RASA models.
using System.Text;
using JSONConversion.Services;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace JSONConversion
{
class Program
{
static void Main(string[] args)
{
string json = JsonConvert.SerializeObject(JSONConversion.Services.JSONHelper.ConvertLUISJSON(JSONHelper.ReadFromFile(#"C:\Users\xyz\Documents\luis.json").Result), new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Formatting.Indented
});
File.WriteAllText(#"C:\Users\xyz\Desktop\RASA\data\examples\RasaFormat.json", json, Encoding.UTF8);
}
}
}
After getting the RASA model, you can just simply train RASA for synonyms.

How to retrieve images from Facebook Graph API in android

I have retrieved json data from facebook graph api requesting GET from
https://graph.facebook.com/YOUR_PAGE_ID/albums?fields=name,photos{picture}&access_token=YOUR_ACCESS_TOKEN/
Json data is as follows:
{
"data": [
{
"name": "School Kids",
"photos": {
"data": [
{
"picture": "https://scontent.xx.fbcdn.net/v/t1.0-0/s130x130/15267641_1789056354665765_6384898034258459703_n.jpg?oh=44daa7be0ac1878e769bc16df444bd0a&oe=58B29329",
"id": "1789056354665765"
},
{
"picture": "https://scontent.xx.fbcdn.net/v/t1.0-0/s130x130/15356660_1789056361332431_834718824553815513_n.jpg?oh=69b3f1b1697808b87eed1e3053a67aaf&oe=58B735FB",
"id": "1789056361332431"
},
{
"picture": "https://scontent.xx.fbcdn.net/v/t1.0-0/s130x130/15356635_1789056401332427_1231396155404307815_n.jpg?oh=3de32d320ac6762adc0dbf8b1ef64e0e&oe=58F69648",
"id": "1789056401332427"
},
{
"picture": "https://scontent.xx.fbcdn.net/v/t1.0-0/s130x130/15380574_1789337074637693_1697389498501034556_n.jpg?oh=ddd57d119882b47172af689abde20cfb&oe=58F15477",
"id": "1789337074637693"
}
],
"paging": {
"cursors": {
"before": "MTc4OTA1NjM1NDY2NTc2NQZDZD",
"after": "MTc4OTMzNzA3NDYzNzY5MwZDZD"
}
}
},
"id": "1789056284665772"
},
{
"name": "Cover Photos",
"photos": {
"data": [
{
"picture": "https://scontent.xx.fbcdn.net/v/t1.0-0/s130x130/14519945_1762073987364002_4539899568406717011_n.jpg?oh=fc8c02e9ced0839eea22d08859b964d0&oe=58BC80D4",
"id": "1762073987364002"
}
],
"paging": {
"cursors": {
"before": "MTc2MjA3Mzk4NzM2NDAwMgZDZD",
"after": "MTc2MjA3Mzk4NzM2NDAwMgZDZD"
}
}
},
"id": "1762074137363987"
},
{
"name": "Profile Pictures",
"photos": {
"data": [
{
"picture": "https://scontent.xx.fbcdn.net/v/t1.0-0/p130x130/14495327_1762072887364112_1611299743258720903_n.jpg?oh=ae87944069fd154e817468a38d9cb4a1&oe=58AE8D02",
"id": "1762072887364112"
}
],
"paging": {
"cursors": {
"before": "MTc2MjA3Mjg4NzM2NDExMgZDZD",
"after": "MTc2MjA3Mjg4NzM2NDExMgZDZD"
}
}
},
"id": "1762072884030779"
}
],
"paging": {
"cursors": {
"before": "MTc4OTA1NjI4NDY2NTc3MgZDZD",
"after": "MTc2MjA3Mjg4NDAzMDc3OQZDZD"
}
}
}
What I want from these data is to get image and album name and display in GridView in android.
My attempt parsing these data is as json object from this method
public async void downloadJsonFeedAsync(string url) {
var httpClient = new HttpClient();
Task < string > contentsTask = httpClient.GetStringAsync(url);
// await! control returns to the caller and the task continues to run on another thread
string content = await contentsTask;
Console.Out.WriteLine("Response Body: \r\n {0}", content);
//Convert string to JSON object
mObject = Newtonsoft.Json.JsonConvert.DeserializeObject < ImageGridItemRootObject > (content);
//Update listview
Activity.RunOnUiThread(() => {
mGridView.Adapter = new PhotoGalleryGridViewAdapter(this.Activity, Resource.Layout.PhotoGalleryGridItemView, mObject.data);
mProgressBar.Visibility = ViewStates.Gone;
});
}
// root object
public class ImageGridItemRootObject
{
public string name { get; set; }
public string photos { get; set; }
public List<ImageGridItem> data { get; set; }
}
//ImageGridItem
public class ImageGridItem
{
private string picture;
private string id;
public ImageGridItem():base()
{
}
public string Picture
{
get { return picture; }
set { picture = value; }
}
public string Id
{
get { return id; }
set { id = value; }
}
}
The problem is I get Picture Null. I wonder which is jSon Object and which is jSon Array so that I can format rootObject in-order to retrieve jSon Array .
Thank you in advance.
If you take the returned JSON and use Edit > Paste Special > Paste JSON as classes in Visual Studio you get the following classes:
public class Rootobject
{
public Datum[] data { get; set; }
public Paging paging { get; set; }
}
public class Paging
{
public Cursors cursors { get; set; }
}
public class Cursors
{
public string before { get; set; }
public string after { get; set; }
}
public class Datum
{
public string name { get; set; }
public Photos photos { get; set; }
public string id { get; set; }
}
public class Photos
{
public Datum1[] data { get; set; }
public Paging1 paging { get; set; }
}
public class Paging1
{
public Cursors1 cursors { get; set; }
}
public class Cursors1
{
public string before { get; set; }
public string after { get; set; }
}
public class Datum1
{
public string picture { get; set; }
public string id { get; set; }
}
It looks like your classes are not matching the JSON, which means the Deserializer does not know what to do with the key/values that do not match in your contract.
Adjust your classes to better match the classes above, and it will deserialize with the image urls.

Resources