I know of [JsonIgnore] which ignores properties altogether, I know of ShouldSerializePropertyName which gives conditional serialization, but I cannot find anything to mark property to be serialized into JSON normally, but not set during deserialization.
I could write a workaround:
[JsonIgnore]
public string MyValue{get;set;}
public string MyValueForJson {get{return MyValue;}
but it is a last resort. Is there some way - other than custom converters etc. - to express that I don't want that field to be populated during deserialization?
As I understand you want to serialize object with all properties in json string but retrieve only selected properties while deserialization on that string.
If this is case then, I had a similar requirement where I created BaseType and DerivedType classes then I serialize derived type into Json string while deserialization I want it in Base type instance. So wrote this code :
using System.Web.Script.Serialization;
public static TB CastToBase<T, TB>(this T derivedTypeInstance)
{
var serializer = new JavaScriptSerializer();
var baseTypeInstance = serializer.Deserialize<TB>(serializer.Serialize(derivedTypeInstance));
return baseTypeInstance;
}
I think you can put [JsonObject(MemberSerialization.OptIn)] property on the class, which requires to explicitly state which properties to serialize. Then you can use both [JsonProperty] and [JsonIgnore] on a property you'd like to serialize as normal but ignore on deserialization.
Example:
[JsonObject(MemberSerialization.OptIn)]
private class UserData
{
[JsonProperty]
public string Token { get; set; }
[JsonProperty]
public string Username { get; set; }
[JsonIgnore]
[JsonProperty]
public string Password { get; set; }
}
Related
Is it possible to deserialize a JSON into a class where a property name could be one of two values?
For example both of these JSONs would deserialize into the same property:
var json1 = "{\"A\":5}";
var json2 = "{\"B\":5}";
I thought that maybe I could use the JsonPropertyName attribute twice.
[JsonPropertyName("A")]
[JsonPropertyName("B")]
public int SomeInt { get; set; }
This is not allowed.
Then I thought maybe if the deserializer could not find the JsonPropertyName attribute it would look for the actual property name.
[JsonPropertyName("A")]
public int B { get; set; }
But that doesn't work either.
You could have two separate properties, with one delegating to another:
[JsonPropertyName("A")]
[Obsolete("Explain why here")]
public int A
{
get => B;
set => B = value;
}
[JsonPropertyName("B")]
public int B { get; set; }
The downside is that both will be written when serializing. I'd originally thought you could use JsonIgnoreAttribute for the obsolete property, but that would prevent it from being deserialized too :( Not so bad if you're only using this for parsing, but unpleasant if you're serializing too.
Additionally, if you ever parse a JSON file with both of them, whichever one is set last will win, which may not be ideal.
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";
}
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.
I have the following sample C# code that is auto-genereated from an xsd using the svcutils.exe application.
[DataContract]
public enum Foo
{
[EnumMember(Value = "bar")]
Bar = 1,
[EnumMember(Value = "baz")]
Baz = 2
}
[DataContract]
public class UNameIt
{
[DataMember(Name = "id")]
public long Id { get; private set; }
[DataMember(Name = "name")]
public string Name { get; private set; }
[DataMember(Name = "foo")]
public Foo Foo { get; private set; }
}
The following is a unit test that attempts to deserialise a sample JSON document to the UNameIt class.
[TestClass]
public class JsonSerializer_Fixture
{
public const string JsonData = #"{ ""id"":123456,
""name"":""John Doe"",
""foo"":""Bar""}";
[TestMethod]
public void DataObjectSimpleParseTest()
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(UNameIt));
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(JsonData));
UNameIt dataObject = serializer.ReadObject(ms) as UNameIt;
Assert.IsNotNull(dataObject);
Assert.AreEqual(123456, dataObject.Id);
Assert.AreEqual(Foo.Baz, dataObject.Foo);
}
}
Unfortunately, the test fails giving the following reason:
System.Runtime.Serialization.SerializationException: There was an
error deserializing the object of type MyNamespace.Units.UNameIt. The
value 'Bar' cannot be parsed as the type 'Int64'.
The test will pass if I update my JSON string to replace the string specifier for the Enum to an integer e.g.
public const string JsonData = #"{ ""id"":123456,
""name"":""John Doe"",
""foo"":""1""}";
I do not have the flexibility to the change the supplied JSON so I have to figure out how to convert the string Enum representation perhaps on serialisation. Ideally, I would like to facilitate this without having to change my autogenerate class because once I re-generate the class I would loose my changes.
I am wondering if it would be possible to extend the DataContractJsonSerializer to custom handle Enumerations? Or perhaps there is better way to do this?
This behavior is by design. Here's a quote from the Enumerations and JSON paragraph on MSDN:
Enumeration member values are treated as numbers in JSON, which is
different from how they are treated in data contracts, where they are
included as member names.
Moreover the DataContractJsonSerializer will automatically serialize all enumerations, so the EnumMemberAttribute is actually ignored.
For a workaround, take a look at this answer on SO.
This is work :
var ret = new JavaScriptSerializer().Deserialize<tblGridProjects>(retApi.Item2);
But you can't use datamembers attributes, so can't rename properties.
You must set the name of the property like Json sended.
Suppose i have one customer class and i will serialize the class to xml. After serialization we will get xml data but i need some property of customer class to be serialized on demand based on few condition. Is it possible?
I have no concept how to do it. Can anyone help me with this?
You can add one or more ShouldSerializeXXXXXX() methods, where XXXXXX is the name of each property you want to serialize based on a condition.
E.g.:
public class Customer
{
[DefaultValue(null)]
public string SomeInfo { get; set; }
[DefaultValue(null)]
public string SomeOtherInfo { get; set; }
#region Serialization conditions
// should SomeInfo be serialized?
public bool ShouldSerializeSomeInfo()
{
return SomeInfo != null; // serialize if not null
}
// should SomeOtherInfo be serialized?
public bool ShouldSerializeSomeOtherInfo()
{
return SomeOtherInfo != null; // serialize if not null
}
#endregion
}
You can use XmlAttributeOverrides and overide the XmlIgnore attribute for your property.
(there is an example in the XmlIgnore msdn page)