How to use AOP (PostSharp) for Serialization? - postsharp

Is it possible to inject code to read/write the properties of an object using a PostSharp aspect? For example, consider the following class:
[ BinarySerializable ]
public class Employee {
public string Name {get; set; }
public string Title {get; set;}
}
In this case, "BinarySerializable" would be a custom aspect that introduces a custom "IBinarySerializable" interface, as follows:
public interface IBinarySerializable
{
void Write(BinaryWriter writer);
void Read(BinaryReader reader);
}
After compilation, the resulting class would look like this:
public class Employee : IBinarySerializable
{
public string Name {get; set;}
public string Title {get; set; }
void IBinarySerializable.Write(BinaryWriter writer)
{
writer.Write(Name);
writer.Write(Title);
}
void IBinarySerializable.Read(BinaryReader reader)
{
Name = reader.ReadString();
Title = reader.ReadString();
}
}
Intuitively, I feel this should be possible using PostSharp, but I need some direction as to the right approach. If this is possible, then how to handle properties that are themselves injected by some other aspect?
UPDATE: I tried creating a simple example using the built-in PSerializable aspect, but ran into problems when members inherit from .NET framework classes that do not have that attribute.
Adding the [PSerializable] attribute to the EmployeeCollection class fails to compile with "Cannot apply [PSerializable] to type 'AOPSerialization.EmployeeCollection' because the base type does not have a [PSerializable] or [Serializer] attribute."
Omitting the [PSerializable] attribute from the EmployeeCollection class throws a runtime PortableSerializationException: Cannot find a serializer for type 'AOPSerialization.EmployeeCollection'.
For example:
[PSerializable]
public class AOPComponent
{
public string Title { get; set; }
public string Description { get; set; }
public AOPComponent(string title, string description){...}
}
[PSerializable]
public class AOPComponentCollection<T> : ObservableCollection<T>
{...}
[PSerializable]
public class EmployeeCollection : AOPComponentCollection<Employee>
{...}
[PSerializable]
public class Company : AOPComponent
{
public EmployeeCollection Engineers { get; set; }
public EmployeeCollection Managers { get; set; }
}
I figured out that the Serializer and ImportSerializer attributes are used to tell the PortableFormatter which custom ISerializer or ISerializerFactory implementation to use.
But the question remains:
How to specify a custom serializer for the generic base collection type?
This approach fails because an attribute may not include type parameters.
[PSerializable, ImportSerializer(typeof(ObservableCollection<T>), typeof(AOPComponentSerializerFactory))]
public class AOPComponentCollection<T> : ObservableCollection<T> where T : AOPComponent
{...}
This approach fails because PostSharp cannot find a serializer for ObservableCollection< T >
[PSerializable, Serializer(typeof(AOPComponentSerializerFactory))]
public class AOPComponentCollection<T> : ObservableCollection<T> where T : AOPComponent
{...}

It would be possible to do that with PostSharp, but only by using the low-level PostSharp SDK, which is undocumented and unsupported.
Good news are that we already implemented this for you, in the namespace PostSharp.Serialization. The aspect is [PSerializable] and the formatter is PortableFormatter.

Related

AutoMapper: Mapping objects with interface properties

my current task needs to pay attention on mapping between different object types and so I recognized the very nice AutoMapper library.
So far easy to handle but these different objects contains complex interface type properties. Let me show you a code snippet:
public inferface IInterface
{
string TextProperty { get; set;}
}
public class A : IInterface
{
string TextProperty { get; set; }
}
public class B : IInterface
{
string TextProperty { get; set; }
}
public inferface IComplexInterface
{
IInterface ComplexProperty { get; set; }
}
public class ComplexA : IComplexInterface
{
IInterface ComplexProperty { get; set; }
}
public class ComplexB : IComplexInterface
{
IInterface ComplexProperty { get; set; }
}
In my case it is possible that class A is mapped to class B and vice versa.
Mapping from type A to B is no problem by configuring CreateMap<A, B>();
Mapping from class ComplexA to class ComplexB throws an exception:
Error mapping types.
Mapping types:
ComplexA -> ComplexB
NamespaceOfComplexA.ComplexA -> NamespaceOfComplexB.ComplexB
Type Map configuration:
ComplexA -> ComplexB
NamespaceOfComplexA.ComplexA -> NamespaceOfComplexB.ComplexB
Property:
ComplexProperty
A possible solution I already found here on stackoverflow could be a configuration as follows:
CreateMap<A, IInterface>().As<B>();
CreateMap<B, IInterface>().As<A>();
But in my case it is not working.
Any suggestions?
Now, I found a solution that works for me.
I use AutoMapper with a non generic approach and so I configure via:
CreateMap(typeof(ComplexA), typeof(ComplexB))
To consider properties with complex types like interfaces or even abstract classes it is possible to write an own ValueResolver that has to implement the interface:
IValueResolver<object, object, object>
with following method:
public object Resolve(object source, object destination, object destMember, ResolutionContext context)
{
//...
}
To resolve interface/abstract class properties you can configure your types by enhancing the configuration with the method ForMember(...) and define a conrete ValueResolver for the particular property as follows:
CreateMap(typeof(ComplexA), typeof(ComplexB)).ForMember("ComplexProperty", x => x.ResolveUsing(new ValueResolver(/*...*/)));
In my case it was the solution to map the interface property to a concrete implementation of my class definitions.
Hope it is useful.

Code first Type per hierarchy

I use EF 5 with the code first approach. Now I try to define a "code" table in which I want to have several different codes (like address code, medium code, etc.). In this table I just have the following properties: ID (Guid), Name (String), Description (String) and a discriminator (in this case something like the type of the code: address code, medium code, etc.).
So I defined the following base class:
public abstract class Code : EntityBase
{
public string Name { get; set; }
public string Beschreibung { get; set; }
}
Then I derived two classes from code
public class AddressCode : Code {}
public class MediumCode : Code {}
The class EntityBase is abstract and just defines the Id property, we use it for every POCO class...
The goal is that I can use AddressCode as a property on my address POCO class:
public class Adresse : EntityBase
{
#region Properties
public string Name1 { get; set; }
public virtual AddressCode AddressCode { get; set; }
#endregion
}
The question now is, how can I explain EF how to do that? Anyone can help?
Thanks
Marco
Thanks for your answer!
I tried to do it like you said. Unfortunately I get an error because of my EntityBase class:
public abstract class EntityBase
{
#region Properties
public virtual Guid Id { get; set; }
public virtual bool IsValid
{
get
{
{
return Validate();
}
}
}
[NotMappedAttribute]
public virtual IList<ValidationFailure> ValidationFailures { get; set; }
#endregion
#region Methods
private bool Validate()
{
var validatorFactory = new AttributedValidatorFactory();
IValidator validator = validatorFactory.GetValidator(GetType());
if (validator == null)
{
return true;
}
ValidationResult validationResult = validator.Validate(this);
ValidationFailures = validationResult.Errors;
return validationResult.IsValid;
}
#endregion
}
The error message is:
You cannot use Ignore method on the property 'ValidationFailures' on type 'Entities.AdresseCode' because this type inherits from the type 'Entities.EntityBase' where this property is mapped. To exclude this property from your model, use NotMappedAttribute or Ignore method on the base type.
As you can see I already defined the property ValidationFailures as NotMapped but still I get this error.. Do you have an idea?
Thanks
Marco
Just create a context (derived from DbContext)
public class AddressesDb : DbContext
{
public DbSet<Code> Codes { get; set; }
public DbSet<Adresse> Adressen { get; set; }
}
And (when used in code) EF will create a database with default table and column names. It will create a discriminator column of type text (nvarchar) which will contain the names of the classes that derive from Code.
If you want different names and/or types you should either use data annotations or fluent API to configure these.
Finally I got it work!
In the DBContext be aware to define DbSets for the code derived classes before all the other POCO's and then it works!

Abstract Properties with a foreign key in Entity Framework 4.1?

UPDATE:
I updated the classes to look more like my actual model. When I remove the Assignable property from the Document base entity, everything works.
Is something like this possible to map in EF 4.1?
public abstract class Entity
{
public Guid Id {get;set;}
}
public abstract class Assignable:Entity
{
}
public class Contact: Assignable
{
public string Name {get;set;}
}
public class Partner: Assignable
{
public string Area {get;set;}
}
public abstract class Document: Entity {
public Guid AssignedToId {get;set}
public Assignable AssignedTo {get;set;
}
public class Submittal: Document
{
public string SomeProperty {get;set;}
}
Mapping:
public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : Entity
{
protected EntityConfiguration()
{
HasKey(e => e.Id);
Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class AssignableEntityMapping<TEntity>: EntityConfiguration<TEntity> where TEntity: Assignable
{
}
public class DocumentEntityMapping<TEntity>: EntityConfiguration<TEntity>
{
public DocumentEntityMapping()
{
HasOptional(e => e.AssignedTo).WithMany().HasForeignKey(e => e.AssignedToId);
}
}
public class ContactMapping: AssignableEntityMapping<Contact>
{
....
}
public class PartnerMapping: AssignableEntityMapping<Partner>
{
....
}
public class SubmittalMapping: DocumentEntityMapping<Submittal>
{
....
}
If this is possible how do I setup the mapping so that the AssignedToId is a foreign key to one of the concrete entities? I created a mapping for the Document entity and I get the error: "The property 'Id' is not a declared property on type..." I am guessing it is because EF doesn't know how to discriminate what the AssignedToId refers to?
I had a lot of extra architecture around the Contact and Partner entities that I could not use something like a TPH (Table Per Hierarchy) approach. EF doesn't know how to map the AssignedToId in the Document class since i was trying to use Table per Concrete Type (TPC) at the same time. I ended up just adding all the "assignable" types to the Document class for now. If there is another way around this, I'd like to know.
public abstract class Document: Entity
{
public Guid? AssignedContactId {get;set;}
public Contact AssignedContact {get;set;}
public Guid? AssignedPartnerId {get;set;}
public Partner AssignedPartner {get;set;}
}

DataAnnotations MetadataType Class Ignores Base Class Properties

I've run into a bit of a wall in trying to use the .NET DataAnnotations feature to provide simple validations in a derived class. I am marking up my class with the standard annotations included in .NET 4 (from the System.ComponentModel.DataAnnotations namespace), then using the MS Enterprise Library v5 Validation Block to process the rules.
I have a number of objects derived from a common base class, which contains properties common to all of my objects. For validation purposes, I may have different rules for the various classes derived from this class.
Here's a simplified example:
public abstract class PersonBase
{
public int Id { get; set; }
public string Name { get; set; }
}
[MetadataType(typeof(CustomerMD))]
public class Customer : PersonBase
{
}
[MetadataType(typeof(ManagerMD))]
public class Manager : PersonBase
{
}
public class CustomerMD
{
[Required]
[StringLength(20, ErrorMessage="Customer names may not be longer than 20 characters.")]
public object Name { get; set; }
}
public class ManagerMD
{
[Required]
[StringLength(30, ErrorMessage = "Manager names may not be longer than 30 characters.")]
public object Name { get; set; }
}
// calling code
var invalidCustomer = new Customer {Id=1, Name=string.Empty};
var valFactory = EnterpriseLibraryContainer.Current.GetInstance<ValidatorFactory>();
var customerValidator = valFactory.CreateValidator<Customer>();
var validationResults = customerValidator.Validate(invalidCustomer);
// validationResults.IsValid should equal False, but actually equals True.
I have found that I can get the expected validation results if I push the annotations down to the base class, but then I lose the ability to fulfill different requirements for different types. Also, if I put class-specific properties on a derived class and provide metadata for these properties, I get results, but only for these properties, not the properties from the base class.
I haven't yet tried using the EntLib provided validation attributes; I'd prefer to keep the library this lives in free of dependencies from outside the core framework, if at all possible.
Am I missing something, or am I just out of luck here?
I think I have a workable solution for this.
It appears that the Metadata class will not provide validation of properties belonging to the superclass of the target object. In order to get Metadata to work with this, I needed to mark the superclass properties as virtual, then provide overrides for the properties that I wanted to validate.
Example (see question above for original example):
public abstract class PersonBase
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
[MetadataType(typeof(CustomerMD))]
partial class Customer : PersonBase
{
public override string Name
{
get
{
return base.Name;
}
set
{
base.Name = value;
}
}
}
With the override in place, the validator works as expected. It's a little more work, but it will get the job done.
I also tried adding annotations to the base class as fallback default rules; this allows me to have a base set of rules and override them as needed on a case by case basis. Looking good.
I run into the same issue and couldn't make it annotate a base class with Attributes using MethadataType. Like Scroll Lock I did the overriding part for base class virtual properties. On top of it I made "shadowing" for the none virtual properties.
public class BaseClass
{
public virtual int Id {get;set;}
public string Name {get;set;}
}
public class DerivedClass
{
[SomeAttribute]
public ovveride int Id {get{ return base.Id;} set{ base.Id = value;}}
[SomeAttribute]
public new string Name {get{ return base.Name;} set{ base.Name = value;}}
}

MVVM && IOC && Sub-ViewModels

I have a ViewModel, it takes two parameters in the constructor that are of the same type:
public class CustomerComparerViewModel
{
public CustomerComparerViewModel(CustomerViewModel customerViewModel1,
CustomerViewModel customerViewModel2)
{
}
}
public class CustomerViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
If I wasn't using IOC I could just new up the viewmodel and pass the sub-viewmodels in. I could package the two viewmodels into one class and pass that into the constructor but if I had another viewmodel that only needed one CustomerViewModel I would need to pass in something that the viewmodel does not need.
How do I go about dealing with this using IOC? I'm using Ninject btw.
Thanks
I'm not familiar with Ninject, but it would seem to me that in order for the IoC to know what CustomerViewModels to Inject into your constructor you would have to setup these objects in advance. Using MEF like attributes and Psuedo code it might look something like...
[Export()]
public class CustomerSelectorViewModel
{
[Export("CustomerA")]
public class CustomerViewModel FirstSelection {get;set;}
[Export("CustomerB")]
public class CustomerViewModel SecondSelection {get;set;}
}
[Export()]
public class CustomerComparerViewModel
{
[ImportingConstructor]
public CustomerComparerViewModel([Import("CustomerA")]CustomerViewModel customerViewModel1, [Import("CustomerB")]CustomerViewModel customerViewModel2)
{
}
}
Here's how to do it in Ninject:
Container.Bind<CustomerViewModel>().ToSelf().WhenTargetHas<CustomerA>();
Container.Bind<CustomerViewModel>().ToSelf().WhenTargetHas<CustomerB>();
Then in the constructor of the class you are using them in:
public class CustomerComparerViewModel
{
public CustomerComparerViewModel([CustomerA]CustomerViewModel customerA,
[CustomerB]CustomerViewModel customerB)
{
}
}