How to pass json data to abstract class? - c#

public abstract class AbstractSearch
{
public string Property { get; set; }
public string TargetTypeName { get; set; }
}
public class DateSearch : AbstractSearch
{
public DateTime? SearchTerm { get; set; }
public DateComparators Comparator { get; set; }
}
public enum DateComparators
{
Less,
LessOrEqual,
Equal,
GreaterOrEqual,
Greater,
InRange
}
public class SearchViewModel
{
public IEnumerable<AbstractSearch> SearchCriteria { get; set; }
}
How to pass above properties to SearchViewModel class from clientside JSON.
I need to pass Property, TargetTypeName, SearchTerm, Comparator from javascript to webapi through Json.
Iam using Web api 2.0 as Serverside. Is it possible to pass Json parameter into Inherited class?

If you specify the concrete type when serializing on the client-side you can make this work using TypeNameHandling. You specify the type using a $type property in the JSON.
The model-binder won't be able to instantiate an abstract-class.
Configure JSON.NET:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
Then post your JSON in this format:
{
"$type": "Namespace.DateSearch, AssemblyName"
"Property": "..."
"etc": ""
}

Related

Create corresponding Model for JSON string to get specific value in C#

I have an API that returns a JSON string and I want to parse that JSON string into an object. I tried creating the object but with no luck. Below is the sample JSON string that I want to get the value from. Any idea as to what the class looks like in order to parse that JSON object into an object? My main concern is to get the code which is "platinum" under currentCard.
{
"status" : {
"currentCard" : {
"code" : "platinum"
},
"status" : {
"index" : 0,
"value" : "This is a sample text."
}
}
}
You need to use a website such as https://json2csharp.com/ or use the inbuilt tools in VS Studio (Edit->Paste Special->Paste JSON as classes) which will automatically create classes from JSON.
The above mentioned website suggests the following:
public class CurrentCard
{
public string code { get; set; }
}
public class Status2
{
public int index { get; set; }
public string value { get; set; }
public CurrentCard currentCard { get; set; }
public Status status { get; set; }
}
public class Root
{
public Status status { get; set; }
}
Which you can then deserialise like this:
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);

WCF Generic result class always is empty

I have this generic class for my server responses:
[DataContract]
public class GenericResult<T>
{
public List<T> ListResult { get; set; }
public T Result { get; set; }
public string Message { get; set; }
}
and this GetAllBrandsTest method to return data to the client:
public async Task<GenericResult<Brand>> GetAllBrandsTest()
{
var result = await repo.GetAllAsync<Brand>();
return new GenericResult<Brand>()
{
ListResult = result.ToList(),
Message = "Success"
};
}
Everything is OK with this methods counterpart GetAllBrands:
public async Task<IList<Brand>> GetAllBrands()
{
return await repo.GetAllAsync<Brand>();
}
But when I call GetAllBrandsTest the result is empty.
[DataContract]
[KnownType(typeof(Brand))]
public class GenericResult<T>
{
[DataMember]
public List<Brand> ListResult { get; set; }
[DataMember]
public Brand Result { get; set; }
[DataMember]
public string Message { get; set; }
}
Any data type transferred between the server-side and the client-side should be explicitly specified how we serialize and deserialize it. Please use the DataContract attribute to specify the data structure the way how to serialize to XML so that the serialization and deserialization can work properly between the service-side and client-side. In addition, for unknown data types, please use the KnownType feature to specify the serialization method in advance.
[DataContract]
[KnownType(typeof(CircleType))]
[KnownType(typeof(TriangleType))]
public class CompanyLogo2
[DataMember]
private Shape ShapeOfLogo;
[DataMember]
private int ColorOfLogo;
}
[DataContract]
public class Shape { }
[DataContract(Name = "Circle")]
public class CircleType : Shape { }
[DataContract(Name = "Triangle")]
public class TriangleType : Shape { }
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-known-types
We either decorate the class with both DataContract attribute and DataMember attribute or remove the DataContract attribute and DataMember attribute. Because the DataContract serializer will be used by default when the complex data type is without specifying any XML serializer.

T object type defined by another string in same class

I'm pulling some data from an external API, and they have some objects defined by a discriminator string.
An example is an array of "Include" objects, where each one can have a different type of object as the Attributes parameter.
public class Include
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("attributes")]
public T Attributes { get; set; }
}
How can I define what object type T is, based on the Type parameter's value?
You could define Attributes as a JObject, then do .ToObject based on what the Type value is.
public class Include
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("attributes")]
public JObject Attributes { get; set; }
}
Then do an if (or switch) statement to handle each Type:
if (include.Type == "TypeOne")
ProcessTypeOne(include.Attributes.ToObject<TypeOne>());
else
...
That's assuming you have a class defined for each possible "Type". Or you can process them however you need to, just convert the Attributes to the necessary Type via the .ToObject<>() method.
You could do something like this:
using System;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
//setup
var a = new Include{Type = "Baz", Attributes = new Baz{Prop1 = "hello"}};
//convert
var b = Convert.ChangeType(a.Attributes, Type.GetType(a.Type));
//use
Console.WriteLine(b.Prop1);
}
}
public class Include
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("attributes")]
public dynamic Attributes { get; set; }
}
public class Baz
{
public string Prop1 { get; set; }
}
Convert.ChangeType would allow you to convert the dynamic object to whatever type it needed to be. However you may still find that you are in same place as #BraianM's answer and will have to type check so you know that a property or method is there.
You could also look at JsonConverter. Perhaps there is something there that would help.

Base Class For JSON Data

I'm creating objects to store the JSON data I will be receiving and cannot figure out the right way to structure the objects. Basically, I can be receiving two different objects that only have differences in the body, so I wish to make a base class.
public class SampleBase
{
public string url { get; set; }
public string resource { get; set; }
public string Body body { get; set; }
}
This is an example of the base, with the Body object declared below
public abstract class Body{ }
I then have two separate files for the versions of the base object I can receive, with an example below:
public class SampleObject : SampleBase
{
public class Body
{
public string bodyproperty { get; set; }
}
}
I am doing this just to be efficient with the classes since they share some properties. The SampleBase class will never be called, instead incoming json will be deserialized into SampleObject. Is this best practice?
Edit: Going by this example, the JSON is received as
{
"url": "xxxxxxxxxx",
"resource": "xxxxxxx",
"body": {
"bodyproperty": "xxxx",
}
}
Your class structure can heavily depend on your choice of serializer. For example, the DataContractJsonSerializer can technically handle inherited classes, but it does it in somewhat of a clunky way. You need to define all the known inheritors of your base type on the base type.
Personally, I would use composition rather than inheritance in your case. Here's an example using the DataContractJsonSerializer:
[DataContract]
public class Wrapper<T> where T : Body
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "resource")]
public string Resource { get; set; }
[DataMember(Name = "body")]
public string T Body { get; set; }
}
[DataContract]
public class Body
{
[DataMember(Name = "bodyproperty")]
public string BodyProperty { get; set; }
}
Then you'd use the class like any other generic.
Wrapper<Body> obj = new Wrapper<Body>();
Edit: Since this is a MVC application, you'll likely be working with the JavascriptSerializer. The DataContract and DataMember can be ignored but the structure of the classes is still relevant.
var serializer = new JavaScriptSerializer();
var data = serializer.Deserialize<Wrapper<Body>>(json);

Bind string to class in controller method

I would like to bind submission of JSON like this
{
"id": 1,
"name": "bob",
"phone": "(425) 882-8080"
}
to...
class Model
{
public int Id { get; set; }
public string Name { get; set; }
public PhoneNumber Phone { get; set; }
}
where the PhoneNumber class is able to bind to the phone string in the JSON.
The idea was the use a json.net custom converter like:
class Model
{
public int Id { get; set; }
public string Name { get; set; }
[JsonConverter(typeof(PhoneNumberCoverter))]
public PhoneNumber Phone { get; set; }
}
The problem is that MVC is not even trying to use the ReadJson method. Model.Phone == null.
I have tried a few things. Hoping that if I had implicit operative overrides to and from string for the PhoneNumber class, it may just do it automatically. Nope.
What is the correct way to customize model binding for this scenario?
I think you expect that when your action method like
public ActionResult Post(Model myModel)
{
// you expect that myModel should has used JSonConverter and provide you data.
}
Above thing will not work as you expected and reason for this JsonConvertor attribute is specific Json.net and not MVC attribute so DefaultModelBinder will not consider that attribute to bind your data.
Possible correct and simple way to do (But not strongly type)
public ActionResult Post(string jsonData)
{
// Now here use Json.net JsonConvert to deserialize string to object of Type Model.
}
Another solution to is to build your own custom modelbinder and use Json.net inside that.

Categories

Resources