Как я могу написать аспект PostSharp для применения атрибута к классу? Рассматриваемый мной сценарий - это объект WCF (или объект домена), который необходимо украсить атрибутом DataContract
. Он также должен иметь свойство Пространство имен
. Примерно так:
using System.Runtime.Serialization;
namespace MWS.Contracts.Search.V1
{
namespace Domain
{
[DataContract(Namespace = XmlNamespaces.SchemaNamespace)]
public class PagingContext
{
[DataMember]
public int Page { get; set; }
[DataMember]
public int ResultsPerPage { get; set; }
[DataMember]
public int MaxResults { get; set; }
}
}
}
В приведенном выше примере вы можете увидеть, как я хочу, чтобы результат выглядел. К классу применен атрибут DataContract. Делать это вручную утомительно и не уникально. Я действительно просто хотел бы написать единственный аспект, который можно было бы применить к моему пространству имен «Домен». Затем он применил бы для меня атрибуты, связанные с сериализацией. Таким образом, я могу просто сосредоточиться на разработке объектов сущностей и не беспокоиться о деталях сериализации.
Я нашел документацию на веб-сайте PostSharp по внедрению кода до, после и вместо методов. Однако я ищу способ ввести атрибут в тип.
Вот решение!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using PostSharp.Aspects;
using PostSharp.Extensibility;
using PostSharp.Reflection;
namespace MWS.Contracts.Aspects
{
// We set up multicast inheritance so the aspect is automatically added to children types.
[MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
[Serializable]
public sealed class AutoDataContractAttribute : TypeLevelAspect, IAspectProvider
{
private readonly string xmlNamespace;
public AutoDataContractAttribute(string xmlNamespace)
{
this.xmlNamespace = xmlNamespace;
}
// This method is called at build time and should just provide other aspects.
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
var targetType = (Type) targetElement;
var introduceDataContractAspect =
new CustomAttributeIntroductionAspect(
new ObjectConstruction(typeof (DataContractAttribute).GetConstructor(Type.EmptyTypes)));
introduceDataContractAspect.CustomAttribute.NamedArguments.Add("Namespace", xmlNamespace);
var introduceDataMemberAspect =
new CustomAttributeIntroductionAspect(
new ObjectConstruction(typeof (DataMemberAttribute).GetConstructor(Type.EmptyTypes)));
// Add the DataContract attribute to the type.
yield return new AspectInstance(targetType, introduceDataContractAspect);
// Add a DataMember attribute to every relevant property.)))
foreach (var property in
targetType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance)
.Where(property =>
property.CanWrite &&
!property.IsDefined(typeof (NotDataMemberAttribute), false)))
yield return new AspectInstance(property, introduceDataMemberAspect);
}
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class NotDataMemberAttribute : Attribute
{
}
}