I have a very simple class called person.
public class Person{
[DataMember(Name="MyName")]
public string Name { get;set;}
}
If I try to serialize or de-serialize, everything works great. In the XML I can see a tag called "MyName" and in the object I see with the VS Intellisense a property called Name.
What I need now is to access, from the object, the serialized name of the property.
For example, I can do object.GetType().GetProperty("Name"); but if I try to do object.GetType().GetProperty("MyName"), the reflection says that the property does not exist. How I can read the serialized name of the property? Is there a way?
It seems that the only way is to access, using reflection, the attributes of the property in this way:
var att = myProperty.GetType().GetAttributes();
var attribute = property.GetCustomAttributes(false)[0] as DataMemberAttribute;
Console.WriteLine(attribute.Name);
This works on both, client and server, without the need of serialize and deserialize the object.
Related
When I set Json.NET to serialize with TypeNameHandling set to TypeNameHandling.Auto, it correctly sets $type for child properties of an object but does not do so for the root object being serialized. Why?
Please consider the following repro:
public class Animal
{
public Animal[] Offspring { get; set; }
}
public class Dog : Animal {}
Animal fido = new Dog
{
Offspring = new Animal[] { new Dog() }
};
var json = JsonConvert.SerializeObject(fido,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
The Json emitted into the json variable is:
{
"Offspring": [{
"$type": "MyApp.Dog, MyApp",
"Offspring": null
}]
}
The Json.NET Documentation says that for TypeNameHandling.Auto the behavior is:
Include the .NET type name when the type of the object being serialized is not the same as its declared type.
My question is - Why does fido not have
"$type": "MyApp.Dog, MyApp", like its puppy? :)
UPDATE: I've found out from the accepted answer to this question that I can force $type to be added by doing this:
var json = JsonConvert.SerializeObject(fido,
typeof(Animal),
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented
});
But my question still holds - Why does Json.NET not do this by itself as per the documentation?
Short answer: it doesn't because it can't.
As you stated in your question, setting TypeNameHandling to Auto directs Json.Net to include the .NET type name when the actual (run-time) type of the object being serialized is not the same as its declared (compile-time) type. In order to do that, Json.Net needs to know both types for every object.
For everything inside the root object, this is straightforward: just get the runtime type of the root object via GetType(), then use reflection to get all of its declared properties and their types, and for each one compare the declared type to the actual type to see if they differ. If they do, output the type name.
But for the root object itself, Json.Net doesn't have access to both types. All the information it has is the object referenced by fido, whose runtime type is Dog. There's no way for Json.Net to discover that the fido variable was declared as Animal, unless you provide that context somehow. And that is exactly why Json.Net provides overloads of SerializeObject which allow you to specify the compile-time type of the object being serialized. You must use one of these overloads if you want the TypeNameHandling.Auto setting to work for the root object.
Brian is absolutely correct, Json.NET has no way of knowing the compile-time declared type of the object it's being passed as the value parameter is declared as an object. The easy fix for this was if Json.NET added generic serialize methods so that the compile-time declared type would automatically flow over to Json.NET but the library's author has decided against my proposal for this here.
As an alternative, I've wrapped all my json (de)serialization needs in a JsonHelper class with generic serialize methods which use the typeof expression to automatically pass the compile-time declared type of the value to be serialized.
Newer versions of Json.Net allow you to pass the expected type to the serialize method
ser.Serialize(stream, rootObject, typeof(BaseClass));
You can pass the base class to the serialize method and TypeNameHandling.Auto will write the $type if the object and expected type do not match.
To best describe what I want to happen, i'll show what i'm doing, as to me it makes sense that this would work ...
public class foo()
{
public foo()
{
MyContext db = new MyContext();
foobar = db.foobar.first();
this = Mapper.Map<bar, foo>(foobar);
}
}
Basically, I want to use automapper within the destination class to map from the source class within the destination classes constructor.
Is there a way to do this?
You cannot do this because this is read only in C#. You cannot assign this a value in the constructor. Not cool to try to change the reference of an object in its constructor. You will have to do the mapping manually and assign each individual property. I would also question if it as a good practice to assign an object values from a database or service in a default constructor. It is not very transparent to the user of the object what is going on and you can get an exception in your constructor.
I have the following class definition whereby the attribute field is hydrated via reflection by NHibernate. The field is not exposed as an object but instead I want to hide it's implementation and just provide properties that reference the properties of the attribute field.
public class CustomerAttribute : ICustomerAttribute
{
private IAttribute attribute;
public string DisplayName
{
get { return attribute.DisplayName;}
}
}
I'm trying to mock this object with RhinoMocks but I'm not sure how to hydrate the attribute field for testing. I've tried setting the attribute field manually via reflection but I get a proxy error from RhinoMocks (which makes sense).
So how do I hydrate the attribute field to I can test the properties of the CustomerAttribute object?
Here is my test right now...
[Test]
public void PropertiesTest()
{
MockRepository mock = new MockRepository();
ICustomerAttribute attribute = mock.StrictMock<ICustomerAttribute>();
//Set the attribute field
FieldInfo fieldInfo = typeof(CustomerAttribute).GetField("attribute",
BindingFlags.Instance | BindingFlags.SetField |
BindingFlags.NonPublic);
fieldInfo.SetValue(attribute, new Domain.Attribute()); //This does not work
Expect.Call(attribute.DisplayName).Return("Postal Code");
mock.ReplayAll();
Assert.AreEqual(true, attribute.DisplayName);
mock.VerifyAll();
}
If CustomerAttribute is your subject under test (SUT) and IAttribute is a dependency that needs to be mocked for testing, IAttribute more than likely needs to be injectable into CustomerAttribute. This should be done either via constructor (usually preferred) or property injection. Look into "Inversion of Control" if you're not familiar with it already.
Also, ICustomerAttribute should NOT be created as a mock--the concrete type should be created explicitly (i.e. "new CustomerAttribute"). After all, CustomerAttribute (the implentation!) is the what you are trying to test.
I am not sure what you are trying to test here. If you want to test your CustomerAttribute class than you need to create an instance of it (instead of mocking ICustomerAttribute).
In order to set the attribute on your CustomerAttribute you could either
Use dependency injection to inject the correct attribute and use it during testing
Use reflection of the real CustomerAttribute instance you created for testing
I have these classes:
[DataContract]
public class ErrorBase {}
[DataContract]
public class FileMissingError: ErrorBase {}
[DataContract]
public class ResponseFileInquiry
{
[DataMember]
public List<ErrorBase> errors {get;set;};
}
An instance of the class ResponseFileInquiry is what my service method returns to the client. Now, if I fill ResponseFileInquiry.errors with instances of ErrorBase, everything works fine, but if I add an instance of inherited type FileMissingError, I get a service side exception during serialization:
Type 'MyNamespace.FileMissingError' with data contract name 'FileMissingError'
is not expected. Add any types not known statically to the list of known types -
for example, by using the KnownTypeAttribute attribute or by adding them to the
list of known types passed to DataContractSerializer.'
So serializer is getting confused because it's expecting the List to contain the declared type objects (ErrorBase) but it's getting inherited type (FileMissingError) objects.
I have the whole bunch of error types and the List will contain combinations of them, so what can I do to make it work?
You should add KnownType attribute to your base class
[DataContract]
[KnownType(typeof(FileMissingError))]
public class ErrorBase {}
Read more about KnownType attribute in this blog
Try this:
[DataContract]
[KnownType(typeof(FileMissingError))]
public class ErrorBase {}
As the error message states, any information that cannot be know statically (like the polymorphic relationship you have expressed here) must be supplied via attributes. In this case you need to specify that your FileMissingError data contract is a known type of its base class, ErrorBase.
A tad bit late, but maybe for future generations. =)
If you don't want to add an attribute for every child class to your parent class, you could construct a list of known types in the parent classes static constructor using
IEnumerable<Assembly> assemblies = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => !a.GlobalAssemblyCache);
IEnumerable<Type> serializableTypes = assemblies.SelectMany(a => a.GetTypes())
.Where(t => IsSerializable(t));
// ...
private static bool IsSerializable(Type type)
{
return type.GetCustomAttributes(true).Any(a => a is DataContractAttribute);
}
and pass this list to the de/serializers constructor. I don't know how robust this solution is, but that's what I am doing and so far it works. It is a little slow, so make sure to cache the result.
I know that a private parameterless constructor works but what about an object with no parameterless constructors?
I would like to expose types from a third party library so I have no control over the type definitions.
If there is a way what is the easiest? E.g. I don't what to have to create a sub type.
Edit:
What I'm looking for is something like the level of customization shown here: http://msdn.microsoft.com/en-us/magazine/cc163902.aspx
although I don't want to have to resort to streams to serialize/deserialize.
You can't really make arbitrary types serializable; in some cases (XmlSerializer, for example) the runtime exposes options to spoof the attributes. But DataContractSerializer doesn't allow this. Feasible options:
hide the classes behind your own types that are serializable (lots of work)
provide binary formatter surrogates (yeuch)
write your own serialization core (a lot of work to get right)
Essentially, if something isn't designed for serialization, very little of the framework will let you serialize it.
I just ran a little test, using a WCF Service that returns an basic object that does not have a default constructor.
//[DataContract]
//[Serializable]
public class MyObject
{
public MyObject(string _name)
{
Name = _name;
}
//[DataMember]
public string Name { get; set; }
//[DataMember]
public string Address { get; set; }
}
Here is what the service looks like:
public class MyService : IMyService
{
#region IMyService Members
public MyObject GetByName(string _name)
{
return new MyObject(_name) { Address = "Test Address" };
}
#endregion
}
This actually works, as long as MyObject is either a [DataContract] or [Serializable]. Interestingly, it doesn't seem to need the default constructor on the client side. There is a related post here:
How does WCF deserialization instantiate objects without calling a constructor?
I am not a WCF expert but it is unlikely that they support serialization on a constructor with arbitrary types. Namely because what would they pass in for values? You could pass null for reference types and empty values for structs. But what good would a type be that could be constructed with completely empty data?
I think you are stuck with 1 of 2 options
Sub class the type in question and pass appropriate default values to the non-parameterless constructor
Create a type that exists soley for serialization. Once completed it can create an instance of the original type that you are interested in. It is a bridge of sorts.
Personally I would go for #2. Make the class a data only structure and optimize it for serialization and factory purposes.