Control ServiceStack deserialization of POST variable and store in object - c#

I would like to deserialize a post variable using ServiceStack's built in deserialization. But, I would like to make two changes that will provide me with some flexibility for another problem that I am attempting to solve.
[Route("/MyObject/{Property}", "POST")]
OtherRoutes...
public class MyObject:IReturn<MyObjectResponse>{
public string Property{ get; set; }
public object Dto{ get; set; }
Other properties...
}
public class CommodityType{
public int Id{ get; set; }
public string CommodityTypeName{ get; set; }
}
If the post variable class name matches {Property}, I want to create that DTO class and store that in the Dto object. I want everything else to deserialize normally.
For example if I post to: "example.com/API/MyObject/CommodityType"
the following json:
{
"CommodityType":{
"Id": 1,
"CommodityTypeName": "Commercial Services"
}
}
if(MyObject.Property == POST.ObjectName){
// in this example Post.ObjectName = "CommodityType"
// Use Reflection to create object of type MyObject.Property
// Deserialize into the object created by reflection
// MyObject.Dto = Deserialized object
}
Is this a situation where I could use Request and Response filters?
Should I create a custom request binder?
Is there another way to approach this?

Not sure if it's an option, but from your example I would be including a property for CommodityType with the type that you want to deserialize into so the JSON Serializer can populate it for you, e.g:
public Request
{
public CommodityType CommodityType { get; set; }
}
It's ok if it doesn't exist as it will just be left as null.
Depending on the shape of the Request DTO property, another option might be to make the dynamic part an object and Configure ServiceStack's JSON Serializer to convert object types to string Dictionary, e.g:
JsConfig.ConvertObjectTypesIntoStringDictionary = true; // in AppHost
public Request
{
public object CommodityType { get; set; }
}
In which case object will be deserialized into a loose-typed Dictionary, which you can inspect change it to a strong type in your Request Filter.
Otherwise if you want to further change the default deserialization behavior, you'll need to use a Custom Request Binder and handle custom deserialization and handle the deserialization yourself.
ServiceStack.Text includes support for parsing arbitrary JSON with JsonObject API's, see links in Custom Deserialization for some examples.

Related

C# convert Json string property to T generic type

I have a class Type with string property Name and T property value. I am receiving a Json object with different properties, two of them are name and value.
I am creating with reflection the Type (in the example I created explicity a boolean) and I need to assign the received String value to the Type.Value property that can be any type.
How can I do that ? The type can be int string, List (any known type) or a new type that I have created. I don't want to switch over the received string type name to create a specific value type.
I want a generic way to do it to avoid updating this method every time that I create a new type in my system. If I create the Type class instance with reflection, I want also to update the value property on runtime without knowing the type.
My code doesn't handle the deserialization (this is taken place in other code that I don't have access to. Even with acess, the project where the deserialize is taken place, doesn't recognize the custom types because it is a common/util project. So in this case, I need to focus only on converting a string value to a T value.
public class Type<T>
{
public string Name { get; set; }
public Type Type => typeof(T)
public T Value { get; set; }
}
public MyResultObject
{
public string ReqId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
var jsonResult = myResultObject //type of MyResultObject
var type = new type<bool>(); //in my code this is created with reflection
type.Name = jsonResult.Name;
type.Value = jsonResult.Value as bool ??? //I want to convert the string Value to the explicit type that can be any T type
The best approach depends on details you haven't included.
If you don't know the type at the point where you're deserializing, but you do know the type at some later point in your code, one solution could be to leave the Value property as a JToken, and then convert it when your code knows what type it needs:
public MyResultObject
{
public string ReqId { get; set; }
public string Name { get; set; }
public JToken Value { get; set; }
}
type.Value = jsonResult.Value<bool>(); // or .Value<T>()
If you need to deserialize the object to the right concrete type but you don't know at compile-time what that type might be, JSON.NET has a built-in feature to handle this: TypeNameHandling. If you serialize and deserialize your objects using serializer options like this:
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
}
... then you can make your Value property an object and JSON.NET will automatically add type metadata into the serialized object so that it can be serialized to the right type.
There are two potential down-sides to that approach, though. One is that you have to be in control of both serialization and deserialization. The other is that there may be security implications if someone you don't trust is providing the JSON: they could instantiate some random object type that you don't expect them to be able to create.
There's a middle-ground approach where you use a custom type converter to determine which type of object to create based on the value of something else on the JSON object, but you have more control over which types of objects might be created, and how that gets represented in the JSON.
Your sample doesn't demonstrate the issue well enough. If you know <T> of Type<T> just add a method on your Type<T> class that does the parsing via JsonConvert from NewtonsoftJson or JsonSerializer from System.Text.Json and problem will be solved. Am I missing something here?
public class Type<T>
{
public string Name { get; set; }
public Type GenericType => typeof(T);
public T Value { get; set; }
public void SetValueFromString(string value)
{
Value = JsonConvert.DeserializeObject<T>(value);
}
}

Using Newtonsoft JsonConvert to serialize and deserialize simple class

I'm trying to simply serialize and deserialize a simple class with JsonConvert.SerializeObject(obj) and JsonConvert.DeserializeObject(string).
I'm using this in a custom TypeConverter for a QueryParameter in .NET Web API Core 2.1.
But I'm getting very strange behavior. My class looks like this:
public class ListRequestDto {
public bool? WithCreator { get; set; }
public int? Skip { get; set; }
public int? Limit { get; set; }
}
And I'm trying to do the following:
var test = new ListRequestDto {
WithCreator = true,
Skip = 0,
Limit = 15
};
string ttt = JsonConvert.SerializeObject(test);
But I'm getting the following output:
"MyNameSpace.ListRequestDto"
If I try it the other way around:
string json = "{ WithCreator: true, Skip: 0, Limit: 15 }";
JsonConvert.DeserializeObject<ListRequestDto>(json);
I get the following exception:
Newtonsoft.Json.JsonSerializationException: "Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'MyNameSpace.ListRequestDto' because the type requires a JSON string value to deserialize correctly.
To fix this error either change the JSON to a JSON string value 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.
Path 'Skip', line 1, position 8."
I tried to remove the nullable fields (replacing them with regular primitives) but that resulted int he exact same error.
The strange thing is, that if I provide the same class as a body it works. And as far as I know Web API Core also uses the Newtonsoft Json Parser.
I do not know why it is necessary, but when I put [JsonObject] on my class it suddenly works.
The exception actually told me to do that, but I do not understand why it is necessary when in no documentation this is used in such a case.
So bascially doing the following solved the problem:
[JsonObject]
public class ListRequestDto {
public bool? WithCreator { get; set; }
public int? Skip { get; set; }
public int? Limit { get; set; }
}

Auto-generate C# classes from JSON, including property initializers

There are a number of great ways to auto-generate C# code from JSON, such as here and here.
However, the resulting code doesn't include property initializers. For example, the following JSON:
{
"Name" : "Blastoise"
}
gets deserialized to this:
public class RootObject
{
public string Name { get; set; }
}
Presumably this is by design, since the values used in the JSON will probably be overridden anyways, so adding initializers might just annoy people who don't want them.
But what if I want that? Short of manually adding every value by hand, is there a way to deserialize JSON to the following?
public class RootObject
{
public string Name { get; set; } = "Blastoise";
}
Obviously in this case a manual edit is easy, but manual editing becomes tedious for larger JSON objects.
is there a way to deserialize JSON to the following?
Using the source code of the converter you mentioned.
A quick change at the line 204
sw.WriteLine(prefix + "public {0} {1} {{ get; set; }} = {2};", field.Type.GetTypeName(), field.MemberName, field.GetExamplesText());
gives me the result similar to what you described
internal class SampleResponse1
{
[JsonProperty("Name")]
public string Name { get; set; } = "Blastoise";
}

How to convert JSON Response to a List in C#?

This might be a basic question but I am stuck while converting a JSON Response to a List.
I am getting the JSON Response as,
{"data":[{"ID":"1","Name":"ABC"},{"ID":"2","Name":"DEF"}]}
Have defined a Class,
class Details
{
public List<Company> data { get; set; }
}
class Company
{
public string ID { get; set; }
public string Name { get; set; }
}
Have tried this for converting,
List<Details> obj=List<Details>)JsonConvert.DeserializeObject
(responseString, typeof(List<Details>));
But this returns an error, saying
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Client.Details]' 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) 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.
Kindly help!
You don't have a List<Detail> defined in your JSON. Your JSON defines one Detail record, which itself has a list of companies.
Just deserialize using Details as the type, not List<Details> (or, if possible, make the JSON wrap the single detail record into a one item array).
You need to Deserialize like this:
var Jsonobject = JsonConvert.DeserializeObject<Details>(json);
using classes generated by json2csharp.com:
var Jsonobject = JsonConvert.DeserializeObject<RootObject>(json);
and your classes should be :
public class Datum
{
public string ID { get; set; }
public string Name { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
}
you can always use json2csharp.com to generate right classes for the json.
You can use JavaScriptDeserializer class
string json = #"{""data"":[{""ID"":""1"",""Name"":""ABC""},{""ID"":""2"",""Name"":""DEF""}]}";
Details details = new JavaScriptSerializer().Deserialize<Details>(json);
EDIT: yes, there's nothing wrong with OP's approach, and Servy's answer is correct. You should deserialize not as the List of objects but as the type that contains that List

Using ServiceStack OrmLite to create Key Value table for dynamic types

I want to create a key value table in my database along the lines of
public class KeyValue {
public string Id { get; set; }
public dynamic Value {get; set; }
}
Using a slightly modified SqlProvider I have no problems getting CreateTable<KeyValue>() to generate varchar(1024) Id, varchar(max) Value.
I have no issues saving objects to it. The problem is when I load the objects
var content = dbConn.GetById<KeyValue>("about");
content.Value at this point is a string.
Looking at the database record, the text for value does not appear to store any type information.
Is there really anything I can do better other than manually invoking ServiceStack.Text and call deserialize with the appropriate type information?
I do not need absolute dynamic, my actual use case is for polymorphism with a base class instead of dynamic. So I don't really care what type Value is whether it's the base class, dynamic, object, etc. Regardless other than using the class
public class KeyValue {
public string Id { get; set; }
public MySpecificChildType Value {get; set; }
}
I haven't been able to get anything other than a string back for Value. Can I tell OrmLite to serialize the type information to be able to correctly deserialize my objects or do I just have to do it manually?
Edit: some further information. OrmLite is using the Jsv serializer defined by ServiceStack.Text.TypeSerializer and is in no way pluggable in the BSD version. If I add a Type property to my KeyValue class with the dynamic Value I can do
var value = content.Value as string;
MySpecificChildType strongType =
TypeSerializer.DeserializeFromString(content, content.Type);
I just really want a better way to do this, I really don't like an object of 1 type going into the db coming back out with a different type (string).
I haven't worked much with the JsvSerializer but with the JsonSerializer you can achieve this (in a few different ways) and as of ServiceStack 4.0.11 you can opt to use the JsonSerializer instead, see https://github.com/ServiceStack/ServiceStack/blob/master/release-notes.md#v4011-release-notes.
Example
public abstract class BaseClass {
//Used for second example of custom type lookup
public abstract string Type { get; set; }
}
public class ChildA : BaseClass {
//Used for second example of custom type lookup
public override string Type { get; set; }
public string PropA { get; set; }
}
And then in your init/bootstrap class you can configure the serializer to emit the type information needed for proper deserialization:
public class Bootstrapper {
public void Init() {
ServiceStack.Text.JsConfig.ExcludeTypeInfo = false;
ServiceStack.Text.JsConfig.IncludeTypeInfo = true;
}
}
If you wish to use something other that the default "__type" attribute that ServiceStack uses (if you for example want to have a friendly name identifying the type rather then namespace/assembly) you can also configure your own custom type lookup as such
public class Bootstrapper {
public void Init() {
ServiceStack.Text.JsConfig.ExcludeTypeInfo = false;
ServiceStack.Text.JsConfig.IncludeTypeInfo = true;
ServiceStack.Text.JsConfig.TypeAttr = "type";
ServiceStack.Text.JsConfig.TypeFinder = type =>
{
if ("CustomTypeName".Equals(type, StringComparison.OrdinalIgnoreCase))
{
return typeof(ChildA);
}
return typeof(BaseClass);
}
}
}

Categories