How can I change properties' names (of auto generated classes) in serialization? - c#

I have a class like below, auto generated by Entity Framework, based in our database:
public partial class TB_Cliente
{
public int IDCliente { get; set; }
public string Nome { get; set; }
// other properties
}
I'm using DataContractJsonSerializer and I need to change the properties' names in serialization. For instance, the property IDCliente must be serialized like ClientID.
I can't use [DataMember] in top of the property, because the class is auto generated, and any future changes will generate the class again and these changes will be lost.
I've had the same problem in the past, when I wanted to use data annotations. I've found the below solution, creating another file and using an interface, which works perfectly:
public interface ITB_Cliente
{
[Required]
string Nome { get; set; }
// other properties
}
[MetadataType(typeof(ITB_Cliente))]
public partial class TB_Cliente : ITB_Cliente
{
}
But this solution doesn't help me now, because (as far as I know) this attribute must be set directly in the class. I've tried to set it in the interface and it didn't work.
Is there a way to change the properties' names in the serialization, in my case? Any help will be greatly appreciated.

You probably want to use DTOs for serialization. I have not tried but AutoMapper can probably do the heavy lifting for you.

I have been trying to overcome a similar problem this week for JSON output from some legacy VB.Net classes that I would prefer not to change if I can avoid it. The serialisation is returning underlying private member names rather than the public property names, e.g. "mFirstName".
Also for autogenerated property names I am getting json like
{"k__BackingField":"Brian","k__BackingField":"Furlong"}
which is not good.
I considered a similar approach to Pawel's above (create DTOs and use Automapper which I have used extensively before).
I am also checking to see if I can make a customised json serialiser but haven't got very far yet.
The third way I have investigated is to create an "Aspect" using PostSharp which will decorate the business entity classes with the DataContract.
This would allow me to create the necessary [DataContract] and [DataMember] attributes on the public properties at compile time without having to modify the legacy code base. As I am using the legacy assemblies within a new WebAPI assembly it effectively extends the code for me.
For guidance / hints please refer to the following links:
For background information http://pietschsoft.com/post/2008/02/NET-35-JSON-Serialization-using-the-DataContractJsonSerializer
For the question that gave the pointer: How to inject an attribute using a PostSharp attribute?
For a walkthrough on how to do something similar which is enough to get going on this: http://www.postsharp.net/blog/post/PostSharp-Principals-Day-12-e28093-Aspect-Providers-e28093-Part-1

Related

How to show the 'discriminator' in generated documentation by Nswag?

we have developed an api and used the tool Nswag to automatically generate the Swagger api documentation. We have some endpoints in our api, where we want to update some fields by using inheritance. For nearer explanation, we have one update method (like POST api/person/{id}) where the user provide a json in the body and by giving the discriminator, the program knows the type, can deserialize the json string and use the right update method, like UpdateAddress or something. When the user does not give this information, then the deserialized object in our client is null and results in errors.
Now there is a problem, that the generated Swagger documentation does not show the discriminator 'property'. It rightly visualizes the inheritance structure with the properties by using this approach:
[JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]
[KnownType(typeof(PersonUpdateAddressCommand))]
public class PersonCommand : CommandBase
{
}
The user does not know, that he have to provide the discriminator property, until we say this to him, but the documentation should be self-explanatory in best case.
To solve this, I added a public string property in the CommandBase class with the name 'discriminator':
public abstract class CommandBase
{
public string discriminator { get; set; }
}
Now it would visualize the property in the documentation, but this seems a bit over the top, because this discriminator 'property' is already existing somewhere in the heap, so why define an extra property?
Is there a way, to show the discriminator in the generated swagger documentation without defining an extra property? Or is this the right approach to add a string property?
The underlying library NJsonschema does not support system.text.json yet hence it doesn't work unless you use json.net as your serializer

What exactly is a Buddy Class and how do I use it to add Annotations to an existing class?

I've seen the term "Buddy class" used as an 'answer' to questions like "how can I add annotations to a partial class in another file" but these answers assume I know what a Buddy Class is, and the code examples assume I understand how/why this works.
I couldn't see a simple explanation of what a buddy class in C# is, and how/why it allows me to modify an existing class such as adding annotations to properties.
‘Buddy class’ is not necessarily C# specific but I believe it is more commonly seen in .Net as its sort of a pattern, or technique (hack), used to extend auto generated classes and add attributes to them.
They are also referred to as associated classes sometimes, or meta data classes. The naming convention is to append MD (for meta data) to the buddy class so it can be identified as one. As for why, well- auto generated code will overwrite any changes you make. Associated classes could be a way to circumvent that, and you could keep your custom meta data (for example validation attributes).
You have one class that is auto generated, handily marked as partial (I believe that is actually why the partial modifier was introduced- to extend auto generated classes).
You want to apply an attribute so you create a separate class that contains that, and you buddy it up with the other class.
If VS generates this for one of your entitites:
public partial class AutoGeneratedClass
{
public string SomeData { get; set; }
}
And you want to extend that and add custom meta data you could create this:
[MetadataType(typeof(NotAutoGeneratedClassMD))]
public partial class AutoGeneratedClass
{
}
public class NotAutoGeneratedClassMD
{
[DisplayName("This is some data")]
public string SomeData { get; set; }
}
Short version:
What: Way to associate classes to extend an auto generated class with custom meta data
Why: Avoid having your changes to an auto generated class be overwritten when generated again.
Personally I'm not a fan, but that is a different story :)

What does [input] mean in C#?

I saw this in saample source code project.
[Input]
public int Length { get; set; }
It was defined in a class:
namespace PowerLanguage.Strategy
{
public class MovAvg_Cross_SE : SignalObject
{
....
What does the [input] mean?
That's an Attribute -- a way to declare information about your source code. What your particular attribute means depends on the namespace of the attribute. You can hover over it to get information on it or (if the declaration is part of your project) ctrl-click on it to see its source.
Its an attribute. The full class name is InputAttribute. Code can reflect over properties and discover attributes, which may modify the behavior or trigger other functionality. Another example of adding functionality is Data Annotations, which when used with something that will discover and run them, can be thought of as adding behavior. You can read more about attributes here (while older, the concept is the same).

PetaPoco and Ignore attribute

I have the following class:
public class Foo
{
public int Id { get; set; }
...
public Boo Boo1 { get; set; }
public Boo Boo2 { get; set; }
}
I want to exclude Boo1 and Boo2 properties but I don't want to decorate those properties with PetaPoco.Ignore attribute. I want to have pure POCO objects. Can I execute Ignore command in code or do I have to create query/stored procedure and manually map all fields?
Any help would be greatly appreciated!
Looks like PetaPoco can't be told in any other way that fields/properties should be ignored than by using attributes. You can either Ignore a few members, or if you're not mapping the majority of a class then you can specify explicit column mapping for the class and decorate the ones you DO want mapped. I understand your hesitance to add ORM-specific cruft to a "pure" POCO, but unfortunately that information has to be somewhere, and as PetaPoco doesn't use mapping files (or much of a configuration at all, really), the class is where it goes.
The only thing you could do is create a DTO/DAO that will be what is mapped, then create implicit or explicit operators to convert between the domain class and its DTO. The DTO, then, can simply not have the fields you don't want to include. That keeps both classes POCO (depending on your feelings regarding operator methods), and it just adds a relatively simple step of casting the query result to your domain class.
In my branch here:
https://github.com/schotime/PetaPoco
You can fluently describe your models like I have described here: http://schotime.net/blog/index.php/2011/05/16/fluent-petapoco-external-mappings/ and also use the convention based mapping like here: http://schotime.net/blog/index.php/2012/02/13/petapoco-convention-based-fluent-mapping/
This is a great place for an anonymous type.
In your method for saving foo
public void InsertFoo(Foo f)
{
var db = new Database("connection");
var petaPocoFooObj = new {f.Id}
db.Insert("FooTable", "FooId", petaPocoFooObj);
}
It's just a little more work, although it could be a PITA if your classes are deeply nested.

Fields vs. Properties and XMLSerializers (101)

So I've been studying the use of various Serializers in the .NET Framework and while trying to experiment on preventing certain objects in a class from being serialized I was thrusted back to some very basic programming questions that I "thought" I knew. Given this example:
public class Example
{
public string examName;
[XmlIgnore]
public int exampleNumber;
public Example()
{ }
[XmlIgnore]
public int ExampleNumberTwo { get; set; }
}
I can create an instance of this class and using the XMLSerializer can output the content of this class in XML format. The [XmlIgnore] attribute actually does what I'd expected; it prevents the serialization of the referenced items.
So venturing further I replaced the [XmlIgnore] declaration for "exampleNumber" with [NonSerializable] expecting the similar results but the output did not change. After searching through resources, it was stated that the [NonSerializable] attribute should only be used on fields and [XmlIgnore] attributes should be used on properties.
Yet another post stated that the [NonSerializable] attribute has no effect when using the XMLSerializer but will produce the expected results when using the SOAP or BinaryFormatter. So I'm lost on the concept at this point.
But this brought me to the basic question, what defines a field vs. a property? I know its a basic question and I've even viewed other discussions here but the degree of clarity I am looking for still wasn't really clear.
I can use the [XmlIgnore] attribute on the property (ExampleNumberTwo) or the variable (exampleNumber) so the statement that it can ONLY be used on Properties doesn't seem correct.
But then again, I have always referred to the objects in my example such as (examName) and (exampleNumber) as being member variables. So what exactly is the signature of a "Field"
Can anyone shed some light on this?
The MSDN documentation supports the idea that [NonSerialized] only gives the expected results with the binary and SOAP serializers:
When using the BinaryFormatter or SoapFormatter classes to serialize
an object, use the NonSerializedAttribute attribute to prevent a field
from being serialized. For example, you can use this attribute to
prevent the serialization of sensitive data.
The target objects for the NonSerializedAttribute attribute are public
and private fields of a serializable class. By default, classes are
not serializable unless they are marked with SerializableAttribute.
During the serialization process all the public and private fields of
a class are serialized by default. Fields marked with
NonSerializedAttribute are excluded during serialization. If you are
using the XmlSerializer class to serialize an object, use the
XmlIgnoreAttribute class to get the same functionality. Alternatively,
implement the ISerializable interface to explicitly control the
serialization process. Note that classes that implement ISerializable
must still be marked with SerializableAttribute.
In terms of "field" vs. "property", fields are straight data variables contained by a class. Properties are actually specially named methods on the class (get_PropName() and set_PropName()). In your code, the compiler allows you to use properties the same way you would use a field, and then inserts the appropriate get/set call for you.
Oftentimes, properties will be simple wrappers around a field:
private int myField;
public int MyProperty
{
get { return myField; }
set { myField = value; }
}
But they don't have to be:
public int TodaysDate
{
get { return DateTime.Today; }
}
In general, you want all your fields to be private, since they're supposed to be implementation details. Any simple data that you'd like to expose should be done via a property, since you can easily surround the data access with (changeable) logic.
In C#, the short answer is that properties have get and/or set methods, while fields do not. VB.NET makes it a little more evident by requiring the "Property" qualifier to be used to differentiate one.
With C#, you can just append " { get; set; }" to the end of a field's definition and it's now a property.
Where this really comes into play is in reflection. Fields and Properties are segregated from one another into different enumerable collections.
This answer to What are the differences between the XmlSerializer and BinaryFormatter will help you get started in the right direction.

Categories

Resources