I want to use ServiceStack JsonSerializer.
I am setting IncludeTypeInfo property true before I serialize my object.And my serialized string contains all type informations like "__type":".Interfacesb,....
When I want to deserialize string that time my interface property null even though I have type information in my serialized string.Is there any other configuration need when deserializing object.
I use two methods
JsonSerializer.SerializeToString and JsonSerializer.DeSerializeFromString
Example:
JsConfig.IncludeTypeInfo = true;
Public Class MyObject
{
Public string a{get;set;}
Public interface b{get;Set;}
}
First, the version 4.* is the continued developed version. 3.9 is not actively maintained by anyone.
Test on servicestack.text 4.50
Secondly i don't think this this property was made to de-serialize it back practical objects.
i did the same in 4.50 and it just doesn't deserialize:
Alternative solutions
Here you can read what to if you want the types from the json: https://stackoverflow.com/a/21603948/1275832.
When you have the type:
I use the following code as an alternative solution (note its an extension method) as a solution for run-time dynamic types (v4.50):
public static object FromJson(this string json, Type deserializeType)
{
return typeof(JsonSerializer).GetMethod("DeserializeFromString", BindingFlags.Static)
.MakeGenericMethod(deserializeType)
.Invoke(null, new[] { json });
}
and usage as: var object = (MyInterface)jsonString.FromJson(Type.GetType(AssemblyQualifiedNameString));
Related
I've got a class containing a Dictionary like this:
Dictionary<string,object> Data
I put data on multiple levels into here, such as:
Data.Add("simple",4);
Data.Add("object",new Dictionary<string,object>{{"key",4}});
Data.Add("array",new List<string>{"a","b","c"});
Then I .Save() it with OrmLite, which is setup to use JSON instead of JSV:
SqliteDialect.Provider.StringSerializer = new JsonStringSerializer();
Looking inside the stored data, using SQL, it looks like perfectly valid JSON.
{
"simple": 4,
"object": {
"key": 4
},
"array": [
"a","b","c"
]
}
However, when I Load() the data back, it doesn't deserialize back to the original.
Here's a link to Gist Cafe, showing the problem:
https://gist.cafe/9ed2bbb3a6a0348f129c493887ae8170
By default JsonStringSerializer uses ServiceStack.Text Typed JSON Serializer which can't deserialize an object back to its original type since that type information is lost, all it sees is the runtime object Type which it leaves as a string since it doesn't know what other object it should deserialize to.
Which is why it's recommended that you serialize typed DTOs so the type information is preserved, e.g:
class CustomData
{
public int Simple { get; set; }
public Dictionary<string,int> Object { get; set; }
}
If you want to deserialize anonymous object data structures into untyped collections you can configure ServiceStack.Text to use JS Utils to handle deserializing arbitrary JSON into untyped data structures by registering it with:
ServiceStack.JS.Configure();
Which I've done in this modified gist:
https://gist.cafe/953f2da51a5077ecf7b5109c14ec2c32
Which outputs the expected result:
{
Id: 1,
Data:
{
simple: 4,
object:
{
key: 4
},
array:
[
a,
b,
c
]
}
}
Whilst it works in this instance because you're using only serializing JSON data types, it wont work if your object dictionary contains complex types because all JS Utils can see is the raw JSON string without any type information, so it's only able to deserialize into untyped collections that matches the JSON object - which is why it's recommended to serialize Typed DTOs so the types are preserved.
What can possible go wrong with this:
public void Main()
{
var input = new StringReader(Document);
var deserializer = new Deserializer(namingConvention: new CamelCaseNamingConvention());
var p = deserializer.Deserialize<Person>(input);
Console.WriteLine(p.Name);
}
public class Person
{
public string Name {get;set;}
}
private const string Document = #"Name: Peter";
A serialization exception is thrown:
Property 'Name' not found on type 'YamlDotNet.Samples.DeserializeObjectGraph+Person'
The same happens if I first serialize a Person object using the Serializer.
While the online sample for deserialization works just fine - this trivial code does not. What am I missing? It must be a stupid little detail. (But it happened before with other data structures I tried.)
As it seems, the problem is with the namingConvention parameter. If I don't set it to an instance of CamelCaseNamingConvention all is fine.
Unfortunately the "canonical" example (https://dotnetfiddle.net/HD2JXM) uses it and thus suggests it is important.
For any reason the CamelCaseNamingConvention converts the fields to lowercase in the class (ie. 'Name' to 'name'). As the string is 'Name' and not 'name' the deserialization fails. The example uses lower-case therefore it works....
I had the same problem....
I have an existing application that sends a Request with a parameter named 'filters'. The 'filters' parameter contains a string that is JSON encoded. Example:
[{"dataIndex":"fieldName", "value":"fieldValue"}, {"dataIndex":"field2", "value":"value2"}].
Using ServiceStack, I would like to bind this as a property on a C# object (class Grid). Is there a preferred method to handle this? Here are the options I can think of. I don't think either 'feel' correct.
Option 1:
I do have a 'ServiceModel' project and this would create a dependency on it which I don't really like.
In AppHost.Configure() method add
RequestBinders[typeof(Grid)] => httpReq => {
return new Grid() {
Filters = new ServiceStack.Text.JsonSerializer<IList<Filter>>().DeserializeFromString(httpReq.QueryString["filters"])
}
}
Option 2:
Seems kind of 'hacky'
public class Grid
{
private string _filters;
public dynamic Filters {
get
{
ServiceStack.Text.JsonSerializer<IList<Filter().DeserializeFromString(_filters);
}
set
{
_filters = value;
}
}
}
You can send Complex objects in ServiceStack using the JSV Format.
If you want to send JSON via the QueryString you can access it from inside your Service of Request filters with something like:
public object Any(Request req) {
var filters = base.Request.QueryString["Filters"].FromJson<List<Filter>>();
}
Note: Interfaces on DTOs are bad practice.
In jcouchdb I used to extend BaseDocument and then, in a transparent manner, mix Annotations and not declared fields.
Example:
import org.jcouchdb.document.BaseDocument;
public class SiteDocument extends BaseDocument {
private String site;
#org.svenson.JSONProperty(value = "site", ignoreIfNull = true)
public String getSite() {
return site;
}
public void setSite(String name) {
site = name;
}
}
and then use it:
// Create a SiteDocument
SiteDocument site2 = new SiteDocument();
site2.setProperty("site", "http://www.starckoverflow.com/index.html");
// Set value using setSite
site2.setSite("www.stackoverflow.com");
// and using setProperty
site2.setProperty("description", "Questions & Answers");
db.createOrUpdateDocument(site2);
Where I use both a document field (site) that is defined via annotation and a property field (description) not defined, both get serialized when I save document.
This is convenient for me since I can work with semi-structured documents.
When I try to do the same with Ektorp I have documents using annotations and Documents using HashMap BUT I couldn't find an easy way of getting the mix of both (I've tried using my own serializers but this seems to much work for something that I get for free in jcouchdb). Also tried to annotate a HashMap field but then is serialized as an object and I get the fields automatically saved BUT inside an object with the name of the HashMap field.
Is it possible to do (easily/for free) using Ektorp?
It is definitely possible. You have two options:
Base your class on org.ektorp.support.OpenCouchDbDocument
Annotate the you class with #JsonAnySetter and #JsonAnyGetter. Red more here: http://wiki.fasterxml.com/JacksonFeatureAnyGetter
I'm trying to re-use some of the model configurations on several entities that implements a interface.
Check this code:
public static void ConfigureAsAuditable<T>(this EntityTypeConfiguration<T> thisRef)
where T : class, IAuditable
{
thisRef.Property(x => x.CreatedOn)
.HasColumnName("utctimestamp")
.IsRequired();
thisRef.Property(x => x.LastUpdate)
.HasColumnName("utclastchanged")
.IsRequired();
} // ConfigureAsAuditable
as you can see I'm trying to call the extension method "ConfigureAsAuditable" on my onmodelcreating method like this:
EntityTypeConfiguration<Account> conf = null;
conf = modelBuilder.Entity<Account>();
conf.ToTable("dbo.taccount");
conf.ConfigureAsAuditable();
When debugging i get this exception:
The property 'CreatedOn' is not a declared property on type
'Account'. Verify that the property has not been explicitly excluded
from the model by using the Ignore method or NotMappedAttribute data
annotation. Make sure that it is a valid primitive property.
Thanks in advance :)
PD:
I'm using EF 5-rc, VS 2011 and .NET Framework 4.5
I think a better approach would be to implement your own derived version of EntityTypeConfiguration. For example:
public class MyAuditableConfigurationEntityType<T> : EntityTypeConfiguration<T>
where T : class, IAuditable{
public bool IsAuditable{get;set;}
}
Then, when building your model, use that new type:
var accountConfiguration = new MyAuditableConfigurationEntityType<Account>();
accountConfiguration.IsAuditable = true; // or whatever you need to set
accountConfiguration.(HasKey/Ignore/ToTable/Whatever)
modelBuilder.Configurations.Add(accountConfiguration);