Returning the following object excludes the property "coordinates" from the JSON.
What am I doing wrong?
[Route("/GeozonePolygon/{ZoneType}")]
public class RequestGeozonePolygon{
public int ZoneType { get; set; }
}
public class ResponseGeozonePolygon{
public FeatureCollection Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
public class GeozonePolygon : Service {
public ResponseGeozonePolygon Any(RequestGeozonePolygon request){
return new ResponseGeozonePolygon() { Result = (new DAL.GeoZone()).GetZoneGeoJsonByType(request.ZoneType) };
}
}
These are the involved types:
public class Geometry {
public string type {
get { return GetType().Name; }
}
}
public class Feature {
public string type {
get { return GetType().Name; }
}
public Geometry geometry { get; set; }
public object properties { get; set; }
}
public class FeatureCollection {
public string type {
get { return GetType().Name; }
}
public Feature[] features { get; set; }
}
public class MultiPolygon : Geometry {
public double[][][][] coordinates { get; set; }
}
FeatureCollection property geometry contains a MultiPolygon object.
Thanks in advance!
You are serializing only the properties of the Geometry object, even though the actual object is a MultiPolygon. As explained by Mythz,
As there is no concept of 'type info' in the JSON spec, in order for inheritance to work in JSON Serializers they need to emit proprietary extensions to the JSON wireformat to include this type info - which now couples your JSON payload to a specific JSON serializer implementation.
To enable support for polymorphic Geometry objects in Servicestack.text, add a type specific config setting to add 'type info' to the output. i.e.:
JsConfig<Geometry>.ExcludeTypeInfo = false;
(may also require adding an interface. See the tests for Polymorphic List serialization. and tests for Polymorphic Instance serialization. for examples)
If you are loath to expose type info in your json, you can use custom serializers as an alternative solution.
Related
I work on my SlackAPI application.
I have created the modal window and when the form from this modal is submitted - I receive a JSON payload that looks like this (not important JSON part is removed)
{
"type":"view_submission",
"view":{
"state":{
"values":{
"IGhn":{
"e5+":{
"type":"static_select",
"selected_option":{
"text":{
"type":"plain_text",
"text":"2021\/8",
"emoji":true
},
"value":"2"
}
}
}
}
},
This payload is processed by my endpoint correctly - except the part - state - values, which are nulls...
I have the models defined like this:
public class View
{
...
[JsonProperty("state")]
public State State { get; set; }
...
}
public class State
{
[JsonProperty("values")]
public Dictionary<string, Values> Values { get; set; }
}
public class Values
{
[JsonProperty()] // <- This is the problem
public Dictionary<string, DynamicValue> something { get; set; }
}
public class DynamicValue
{
[JsonProperty("selectedOptions")] // <- This is null
public Dictionary<string, SelectedOption> SelectedOptions { get; set; }
}
If the values (property names) will be static it will be okay, but the problem is, that : IGhn / e5+ are dynamically changing - so the deserialization does not work...
Must say that the whole JSON is deserialized correctly, but I can't deserialize the rest in under IGhn (I even don't know how to create class for it...do the deserializer know what to do.... )
Ok - I found the solution:
I have changed the class State:
public class State
{
[JsonProperty("values")]
public Dictionary<string, Dictionary<string, ParentForSelectedOption>> Values { get; set; }
}
Then Object ParentForSelectedOption is deserialized in a regular way - so these dynamic names were solved by the use of Dictionaries
and these can be removed:
public class Values
{
[JsonProperty()] // <- This is the problem
public Dictionary<string, DynamicValue> something { get; set; }
}
public class DynamicValue
{
[JsonProperty("selectedOptions")] // <- This is null
public Dictionary<string, SelectedOption> SelectedOptions { get; set; }
}
I a class that looks like so:
public class AccountAddress
{
[Key]
public int accountNumber { get; set; }
public int rowNumber { get; set; }
public string civicaddress { get; set; }
public AccountAddress()
{
//Default constructor
}
}
There is a rest API that returns a List of AccountAddress as oData that looks like this to a variable "result":
{
"#odata.context":"http://localhost:52139/odata/$metadata#WEB_V_CIVIC_ADDRESS/Values.Classes.Entities.AccountAddress","value":[
{
"#odata.type":"#Values.Classes.Entities.AccountAddress","accountNumber":123456,"rowNumber":0,"civicaddress":"123 FAKE EAST DRIVE"
},{
"#odata.type":"#Values.Classes.Entities.AccountAddress","accountNumber":123457,"rowNumber":0,"civicaddress":"123 FAKE WEST DRIVE"
}
]
}
When I try to use:
var addressAccountLookup = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AccountAddress>>(result);
I get an error
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[ATPublicTAX.Regina.ca.Values.Classes.Entities.AccountAddress]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
Any help on this would be greatly appreciated.
Thanks.
You're passing the entire object to your deserialization method. You need to pass only the array, which is what it's asking you to do.
JArray array = (JArray) result["value"];
var addressAccountLookup = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AccountAddress>>(array);
Something like that should work.
The solution that I got to work is create a class:
private class oDataResponse<T>
{
public List<T> Value { get; set; }
}
Then deserialize like this:
var oDataRespone = Newtonsoft.Json.JsonConvert.DeserializeObject<oDataResponse<AccountAddress>>(result);
So it happens that you can prevent breeze json serialization of some properties using data annotations on your model by like this(well if you are using EF6 with JSON.NET on the backend)...
[Table("Project")]
public partial class Project
{
public Project()
{
}
public int id { get; set; }
[JsonIgnore]
public bool NoLongerExist { get; set; }
}
By doing so the property becomes invisible on this endpoint used by breeze
public IQueryable<Project> Projects()
{
return _db.Context.Projects.Where(o => o.NoLongerExist == true);
}
Can i apply [JsonIgnore] based on a certain condition like an authenticated user or a random if from this endpoint?
JSON deserialization not working for polymorphic attribute behavior-
Sample code -
--MODEL
public class A
{
public string a_property { get; set; }
}
public class B : A
{
public string b_property { get; set; }
}
public class C
{
public A a { get; set; }
}
--API
public partial class TestController : ApiBaseController
{
[HttpGet]
public IHttpActionResult GetC()
{
return Ok<C>(new C(){a = new B(){a_property="test", b_property ="test1"}});
}
[HttpPost]
public IHttpActionResult SaveC(C c)
{
return Ok<C>(c);
}
}
--Web Route config
Config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
Config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
Config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.All;
From UI GetC API is called the object returned is C with attribute a of type B. It does have the type detail i.e. [$type A, assembly name]. When the same JSON is posted from client to call SaveC API the deserialized JSON is of type C but the attribute a is of type A instead of B.
I have searched the web but with no help, what am i missing?
JSON.net deserializer is just respecting your model, if you want specify the heritage level for your entity, you need to create a custom converter or you can work with an interface and just use a jsonconvert attribute.
I have an object which I am de-serializing using ToJson<>() method from ServiceStack.Text namespace.
How to omit all the GET only propeties during serialization? Is there any attribute like [Ignore] or something that I can decorate my properties with, so that they can be omitted?
Thanks
ServiceStack's Text serializers follows .NET's DataContract serializer behavior, which means you can ignore data members by using the opt-out [IgnoreDataMember] attribute
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
[IgnoreDataMember]
public string IsIgnored { get; set; }
}
An opt-in alternative is to decorate every property you want serialized with [DataMember]. The remaining properties aren't serialized, e.g:
[DataContract]
public class Poco
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public string IsIgnored { get; set; }
}
Finally there's also a non-intrusive option that doesn't require attributes, e.g:
JsConfig<Poco>.ExcludePropertyNames = new [] { "IsIgnored" };
Dynamically specifying properties that should be serialized
ServiceStack's Serializers also supports dynamically controlling serialization by providing conventionally named ShouldSerialize({PropertyName}) methods to indicate whether a property should be serialized or not, e.g:
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
public string IsIgnored { get; set; }
public bool? ShouldSerialize(string fieldName)
{
return fieldName == "IsIgnored";
}
}
More examples in ConditionalSerializationTests.cs
For nullable members, you also have the ability to set it to null before serializing.
This is particularly useful if you want to create a single view/api model that is re-used for several API calls. The service can touch it up before setting it on the response object.
Example:
public SignInPostResponse Post(SignInPost request)
{
UserAuthentication auth = _userService.SignIn(request.Domain, true, request.Username, request.Password);
// Map domain model ojbect to API model object. These classes are used with several API calls.
var webAuth = Map<WebUserAuthentication>(auth);
// Exmaple: Clear a property that I don't want to return for this API call... for whatever reason.
webAuth.AuthenticationType = null;
var response = new SignInPostResponse { Results = webAuth };
return response;
}
I do wish there was a way to dynamically control the serialization of all members (including non-nullable) on a per endpoint fashion.