The objective is to instantiate local:MyViewModel without constructor injection as well as without static resource.
The property element syntax version below works fine.
<Label.BindingContext>local:MyViewModel</Label.BindingContext>
My attempt with XML attribute syntax below also works.
<Label ... BindingContext="{local:MyViewModel}"/>
However Visual Studio Community warns me with
Type local:MyViewModel is used like a markup extension but does not derive from MarkupExtension.
Question:
Is it safe to ignore this warning?
Is there any trick to suppress the warning?
Here is the markup extension implementation for WPF. Check if it will work in Xamarin too.
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Markup;
namespace CommonCore
{
[MarkupExtensionReturnType(typeof(Type))]
public class CreateInstanceExtension : MarkupExtension
{
[ConstructorArgument("instanceType")]
[DefaultValue(null)]
public Type InstanceType { get; set; }
[ConstructorArgument("instanceValue")]
[DefaultValue(null)]
public string InstanceValue { get; set; }
public CreateInstanceExtension(Type instanceType, string instanceValue)
: this(instanceValue)
{
InstanceType = instanceType;
}
public CreateInstanceExtension(string instanceValue)
: this()
{
InstanceValue = instanceValue;
}
public CreateInstanceExtension()
{ }
private static TypeExtension typeExtension;
public override object ProvideValue(IServiceProvider serviceProvider)
{
Type type = InstanceType;
string value = InstanceValue;
if (type is null)
{
value = value?.Trim(" \t\r\n".ToCharArray());
if (!string.IsNullOrEmpty(value))
{
string typeName = null;
if (value[0] == '(')
{
int end = value.IndexOf(')');
if (end > 0)
{
typeName = value.Substring(1, end - 1);
value = value.Substring(end + 1).Trim(" \t\r\n".ToCharArray());
}
}
else
{
typeName = value;
value = null;
}
if (!string.IsNullOrEmpty(typeName))
{
(typeExtension ??= new TypeExtension()).TypeName = typeName;
type = (Type)typeExtension.ProvideValue(serviceProvider);
}
}
}
if (type is null)
{
throw new NullReferenceException("The type must be specified.");
}
if (string.IsNullOrEmpty(value))
{
return Activator.CreateInstance(type);
}
else
{
if (TypeDescriptor.GetConverter(type) is not TypeConverter converter)
{
throw new NotImplementedException("There is no TypeConverter for the specified type.");
}
var target = ((IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)))?.TargetObject as FrameworkElement;
if (target?.Language.GetEquivalentCulture() is CultureInfo culture)
return converter.ConvertFromString(null, culture, value);
return converter.ConvertFromInvariantString(value);
}
}
}
}
Usage in WPF:
<Label ... DataContext="{commcore:CreateInstance (local:MyViewModel)}"/>
<Label ... DataContext="{commcore:CreateInstance local:MyViewModel}"/>
<Label ... DataContext="{commcore:CreateInstance (sys:Double)123.456}"/>
Is there a way to ignore get-only properties using the Json.NET serializer but without using JsonIgnore attributes?
For example, I have a class with these get properties:
public Keys Hotkey { get; set; }
public Keys KeyCode
{
get
{
return Hotkey & Keys.KeyCode;
}
}
public Keys ModifiersKeys
{
get
{
return Hotkey & Keys.Modifiers;
}
}
public bool Control
{
get
{
return (Hotkey & Keys.Control) == Keys.Control;
}
}
public bool Shift
{
get
{
return (Hotkey & Keys.Shift) == Keys.Shift;
}
}
public bool Alt
{
get
{
return (Hotkey & Keys.Alt) == Keys.Alt;
}
}
public Modifiers ModifiersEnum
{
get
{
Modifiers modifiers = Modifiers.None;
if (Alt) modifiers |= Modifiers.Alt;
if (Control) modifiers |= Modifiers.Control;
if (Shift) modifiers |= Modifiers.Shift;
return modifiers;
}
}
public bool IsOnlyModifiers
{
get
{
return KeyCode == Keys.ControlKey || KeyCode == Keys.ShiftKey || KeyCode == Keys.Menu;
}
}
public bool IsValidKey
{
get
{
return KeyCode != Keys.None && !IsOnlyModifiers;
}
}
Do I need to add [JsonIgnore] to all of them (I also have many other classes), or there is better way to ignore all get-only properties?
You can do this by implementing a custom IContractResolver and using that during serialization. If you subclass the DefaultContractResolver, this becomes very easy to do:
class WritablePropertiesOnlyResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
return props.Where(p => p.Writable).ToList();
}
}
Here is a test program demonstrating how to use it:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
class Program
{
static void Main(string[] args)
{
Widget w = new Widget { Id = 2, Name = "Joe Schmoe" };
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new WritablePropertiesOnlyResolver()
};
string json = JsonConvert.SerializeObject(w, settings);
Console.WriteLine(json);
}
}
class Widget
{
public int Id { get; set; }
public string Name { get; set; }
public string LowerCaseName
{
get { return (Name != null ? Name.ToLower() : null); }
}
}
Here is the output of the above. Notice that the read-only property LowerCaseName is not included in the output.
{"Id":2,"Name":"Joe Schmoe"}
Use the OptIn mode of JSON.net and you'll only need to decorate the properties you want to serialize. This isn't as good as automatically opting out all read only properties, but it can save you some work.
[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty]
public string serializedProp { get; set; }
public string nonSerializedProp { get; set; }
}
Udate: Added another possibility using reflection
If the above solution still isn't quite what you're looking for, you could use reflection to make dictionary objects which would then be serialized. Of course the example below will only work for simple classes, so you would need to add recursion if your classes contain other classes. This should at least point you in the right direction.
The subroutine to put the filtered result into a dictionary:
private Dictionary<String, object> ConvertToDictionary(object classToSerialize)
{
Dictionary<String, object> resultDictionary = new Dictionary<string, object>();
foreach (var propertyInfo in classToSerialize.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (propertyInfo.CanWrite) resultDictionary.Add(propertyInfo.Name, propertyInfo.GetValue(classToSerialize, null));
}
return resultDictionary;
}
A snippet showing its use:
SampleClass sampleClass = new SampleClass();
sampleClass.Hotkey = Keys.A;
var toSerialize = ConvertToDictionary(sampleClass);
String resultText = JsonConvert.SerializeObject(toSerialize);
You can use a contract resolver like this:
public class ExcludeCalculatedResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = _ => ShouldSerialize(member);
return property;
}
internal static bool ShouldSerialize(MemberInfo memberInfo)
{
var propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo == null)
{
return false;
}
if (propertyInfo.SetMethod != null)
{
return true;
}
var getMethod = propertyInfo.GetMethod;
return Attribute.GetCustomAttribute(getMethod, typeof(CompilerGeneratedAttribute)) != null;
}
}
It will exclude calculated properties but include C#6 get only properties and all properties with a set method.
Json.net does have the ability to conditionally serialize properties without an attribute or contract resolver. This is especially useful if you don't want your project to have a dependency on Json.net.
As per the Json.net documentation
To conditionally serialize a property, add a method that returns boolean with
the same name as the property and then prefix the method name with
ShouldSerialize. The result of the method determines whether the
property is serialized. If the method returns true then the property
will be serialized, if it returns false then the property will be
skipped.
When using Json.Net, I understand how to get the $type property into the rendered json, but is there a way to change that field name? I need to use "__type" instead of "$type".
http://json.codeplex.com/workitem/22429
"I would rather keep $type hard coded and consistent."
Consistent with what I wonder?
http://json.codeplex.com/workitem/21989
I would rather not - I think this is too specific to me and I don't
want to go overboard with settings. At some point I will probably
implement this - http://json.codeplex.com/workitem/21856 - allowing
people to read/write there own meta properties in the JSON and you
could reimplement type name handling with a new property name. The
other option is just to modify the source code for yourself to have
that property name.
And more recently, Issue #36: Customizable $type property name feature:
I'd rather not
This is my solution...
json.Replace("\"$type\": \"", "\"type\": \"");
Looks like this is hardcoded as public const string TypePropertyName = "$type"; in Newtonsoft.Json.Serialization.JsonTypeReflector which is internal static class unfortunately.
I needed this myself, and the only thing I can think of is having custom modified version of json.net itself. Which is of course is a major pita.
when serializing, there is a nice way to override the property name:
public class CustomJsonWriter : JsonTextWriter
{
public CustomJsonWriter(TextWriter writer) : base(writer)
{
}
public override void WritePropertyName(string name, bool escape)
{
if (name == "$type") name = "__type";
base.WritePropertyName(name, escape);
}
}
var serializer = new JsonSerializer();
var writer = new StreamWriter(stream) { AutoFlush = true };
serializer.Serialize(new CustomJsonWriter(writer), objectToSerialize);
I haven't tried deserialization yet, but in worst case I could use:
json.Replace("\"__type": \"", "\"type\": \"$type\");
I had to do this for my UI REST API as Angular.js disregards fields names starting with a dollar sign ($).
So here's a solution that renames $type to __type for the whole Web API and works both for serialization and deserialization.
In order to be able to use a custom JsonWriter and a custom JsonReader (as proposed in the other answers to this question), we have to inherit the JsonMediaTypeFormatter and override the corresponding methods:
internal class CustomJsonNetFormatter : JsonMediaTypeFormatter
{
public override JsonReader CreateJsonReader(Type type, Stream readStream, Encoding effectiveEncoding)
{
return new CustomJsonReader(readStream, effectiveEncoding);
}
public override JsonWriter CreateJsonWriter(Type type, Stream writeStream, Encoding effectiveEncoding)
{
return new CustomJsonWriter(writeStream, effectiveEncoding);
}
private class CustomJsonWriter : JsonTextWriter
{
public CustomJsonWriter(Stream writeStream, Encoding effectiveEncoding)
: base(new StreamWriter(writeStream, effectiveEncoding))
{
}
public override void WritePropertyName(string name, bool escape)
{
if (name == "$type") name = "__type";
base.WritePropertyName(name, escape);
}
}
private class CustomJsonReader : JsonTextReader
{
public CustomJsonReader(Stream readStream, Encoding effectiveEncoding)
: base(new StreamReader(readStream, effectiveEncoding))
{
}
public override bool Read()
{
var hasToken = base.Read();
if (hasToken && TokenType == JsonToken.PropertyName && Value != null && Value.Equals("__type"))
{
SetToken(JsonToken.PropertyName, "$type");
}
return hasToken;
}
}
}
Of course you need to register the custom formatter in your WebApiConfig. So we replace the default Json.NET formatter with our custom one:
config.Formatters.Remove(config.Formatters.JsonFormatter);
config.Formatters.Add(new CustomJsonNetFormatter());
Done.
We had a need for this so I created a custom JsonReader. We're are using rest in our MS web services with complex data models and needed to replace the "__type" property with "$type."
class MSJsonReader : JsonTextReader
{
public MSJsonTextReader(TextReader reader) : base(reader) { }
public override bool Read()
{
var hasToken = base.Read();
if (hasToken && base.TokenType == JsonToken.PropertyName && base.Value != null && base.Value.Equals("__type"))
base.SetToken(JsonToken.PropertyName, "$type");
return hasToken;
}
}
Here is how we use it.
using(JsonReader jr = new MSJsonTextReader(sr))
{
JsonSerializer s = new JsonSerializer();
s.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
s.NullValueHandling = NullValueHandling.Ignore;
s.TypeNameHandling = TypeNameHandling.Auto; // Important!
s.Binder = new MSRestToJsonDotNetSerializationBinder("Server.DataModelsNamespace", "Client.GeneratedModelsNamespace");
T deserialized = s.Deserialize<T>(jr);
return deserialized;
}
Here is our MSRestToJsonDotNetSerializationBinder that completes the compatibility between MS rest and Json.Net.
class MSRestToJsonDotNetSerializationBinder : System.Runtime.Serialization.SerializationBinder
{
public string ServiceNamespace { get; set; }
public string LocalNamespace { get; set; }
public MSRestToJsonDotNetSerializationBinder(string serviceNamespace, string localNamespace)
{
if (serviceNamespace.EndsWith("."))
serviceNamespace = serviceNamespace.Substring(0, -1);
if(localNamespace.EndsWith("."))
localNamespace = localNamespace.Substring(0, -1);
ServiceNamespace = serviceNamespace;
LocalNamespace = localNamespace;
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = string.Format("{0}:#{1}", serializedType.Name, ServiceNamespace); // MS format
}
public override Type BindToType(string assemblyName, string typeName)
{
string jsonDotNetType = string.Format("{0}.{1}", LocalNamespace, typeName.Substring(0, typeName.IndexOf(":#")));
return Type.GetType(jsonDotNetType);
}
}
You could also do it this way:
[JsonConverter(typeof(JsonSubtypes), "ClassName")]
public class Annimal
{
public virtual string ClassName { get; }
public string Color { get; set; }
}
You will need the JsonSubtypes
converter that is not part of Newtonsoft.Json project.
There is another option that allows to serialize custom type property name in Json.NET. The idea is do not write default $type property, but introduce type name as property of class itself.
Suppose we have a Location class:
public class Location
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
First, we need to introduce type property name and modify the class as demonstrated below:
public class Location
{
[JsonProperty("__type")]
public string EntityTypeName
{
get
{
var typeName = string.Format("{0}, {1}", GetType().FullName, GetType().Namespace);
return typeName;
}
}
public double Latitude { get; set; }
public double Longitude { get; set; }
}
Then, set JsonSerializerSettings.TypeNameHandling to TypeNameHandling.None in order the deserializer to skip the rendering of default $type attribute.
That's it.
Example
var point = new Location() { Latitude = 51.5033630, Longitude = -0.1276250 };
var jsonLocation = JsonConvert.SerializeObject(point, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None, //do not write type property(!)
});
Console.WriteLine(jsonLocation);
Result
{"__type":"Namespace.Location, Namespace","Latitude":51.503363,"Longitude":-0.127625}
Using a custom converter should get the job done.
public CustomConverter : JsonConverter
{
public override bool CanWrite => true;
public override bool CanRead => true;
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
=> throw new NotImplementedException();
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
var jOjbect = (JObject)JToken.FromObject(value);
jOjbect.Add(new JProperty("type", value.GetType().Name));
jOjbect.WriteTo(writer);
}
}
I am getting an exception when I attempt to serialize the following classes using Json.Net:
[Serializable]
[DataContract(Name = "child", Namespace = "")]
public class Child
{
[DataMember(Name = "id", EmitDefaultValue = false)]
public int Id { get; set; }
}
[Serializable]
[DataContract(Name = "parent", Namespace = "")]
public class Parent
{
[DataMember(Name = "id", EmitDefaultValue = false)]
public int Id { get; set; }
[DataMember(Name = "children", EmitDefaultValue = false)]
public List<Child> Children { get; set; }
public override bool Equals(object obj)
{
Parent parent = (Parent)obj;
return parent.Id.Equals(Id);
}
}
Here is the serialization code:
SortedDictionary<int, Parent> parents = new SortedDictionary<int, Parent>
{
{
1,
new Parent
{
Id = 1,
Children = new List<Child>
{
new Child
{
Id = 2
}
}
}
}
};
string json = JsonConvert.SerializeObject(parents);
Here is the exception:
System.InvalidCastException was unhandled by user code
Message=Unable to cast object of type 'System.Collections.Generic.List`1[Child]' to type 'Parent'.
If I remove the Equals override method, the serialization occurs without error. If, instead I remove the List<Child> property from the Parent class the serialization also works without error.
Can someone please help to me understand why the override method appears to break serialization in this way? Is there a way around it?
I'll bet you $1 that this issue has nothing to do with the use of override methods in the class being serialized. It's the unchecked cast in Equals(). The serialization code may call .Equals() to check for cycles or for any other reason - I'll bet this fixes the problem:
public override bool Equals(object obj)
{
Parent parent = obj as Parent;
return (parent != null) && parent.Id.Equals(Id);
}
I have a wcf service and I have class like below:
public class Message
{
[XmlElement(ElementName = "message")]
[DataMember(Name = "message")]
public string message { get; set; }
[XmlElement(ElementName = "MsgID")]
[DataMember(Name = "MsgID")]
public string MsgID{ get; set; }
}
Then i browsed my service in a browser the xml i am getting like below:
<MessageResponse>
<Status>SUCCESS</Status>
<a:Message>
<a:message>msg1</a:message>
<a:MsgID>1</a:MsgID>
</a:Message>
</MessageResponse>
My Service Contract is Like below:
and one more important thing is:MessageDco class is a copy of Message Class
[ServiceContract()]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class UserLoginProfileService
{
[WebGet(UriTemplate = "/GetMessages?MsgID={MsgID}")]
public MessageResponse GetMessage(Guid MsgID)
{
MessageResponse objMessageResponse = new MessageResponse();
try
{
Message objMessage = new MessageFacade().GetMessage(MsgID);
if (objUserLoginProfile != null)
{
MessageResponse.Status = Status.Success;
MessageResponse.Messages = Mapper.ToDataContractObjects(Message);
}
else
{
objMessageResponse.Status = Status.Success;
}
}
catch (Exception ex)
{
objMessageResponse.Status = Status.Failure;
}
return objMessageResponse;
}
}
public class MessageResponse
{
[XmlElement(ElementName = "Messages")]
[DataMember(Name = "Messages")]
public MessageDco[] Messages { get; set; }
[XmlElement(ElementName = "Status")]
[DataMember(Name = "Status")]
public string Status { get; set; }
}
My mapper class is like below:
public sealed class Mapper
{
public static MessageDco[] ToDataContractObjects(IEnumerable<MessageDco> objMessageDco)
{
if (objMessageDco != null)
{
return objMessageDco.Select(a => ToDataContractObjects(a)).ToArray();
}
else
{
return null;
}
}
}
if we see "a:" is added to the tags. why it is added? i am unable remove that "a:" from the tags. Please help me how to remove "a:" from Tags. And also if you see Status tag is coming correct.
Thanks in advance.
If you're only using the DataContractSerializer you don't need the XmlElement attribute
Further more you should use a DataContract attribute on all classes and specify the namespaces, because they are defined implicitly if they are missing. Different classes may have difference XML namespaces.
The MessageResponse object has a Messages array of MessageDco object but the sample XML supplied does not match, I would expect a Messages element containing a set of Message elements.