How to Inject an Attribute Using a Postsharp Attribute

How to inject an attribute using a PostSharp attribute?

See http://www.sharpcrafters.com/blog/post/PostSharp-Principals-Day-12-e28093-Aspect-Providers-e28093-Part-1.aspx

Here is a working example. Applying this aspect to a class will apply the XmlIgnore attribute to any public property that does not already have XmlElement or XmlAttribute applied to it. the trick is using the CustomAttributeIntroductioinAspect that is built in to Postsharp. You just need to instantiate an instance specifying the attribute type and contructor details, then create a provider to apply it to the target(s).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Extensibility;
using PostSharp.Aspects;
using PostSharp.Reflection;
using System.Xml.Serialization;

namespace ApplyingAttributes
{
[MulticastAttributeUsage(MulticastTargets.Field | MulticastTargets.Property,
TargetMemberAttributes = MulticastAttributes.Public | MulticastAttributes.Instance)]
public sealed class AddXmlIgnoreAttribute : LocationLevelAspect, IAspectProvider
{
private static readonly CustomAttributeIntroductionAspect customAttributeIntroductionAspect =
new CustomAttributeIntroductionAspect(
new ObjectConstruction(typeof(XmlIgnoreAttribute).GetConstructor(Type.EmptyTypes)));

public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
LocationInfo memberInfo = (LocationInfo)targetElement;

if (memberInfo.PropertyInfo.IsDefined(typeof(XmlElementAttribute), false) ||
memberInfo.PropertyInfo.IsDefined(typeof(XmlAttributeAttribute), false))
yield break;

yield return new AspectInstance(memberInfo.PropertyInfo, customAttributeIntroductionAspect);
}
}

}

To use attributes, specifying parameters, I use

 public class MyAspect : TypeLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
yield return Create<MethodInfo>(mi, "Value");

}

private AspectInstance Create<T>(T target, string newName)
{
var x = new CustomAttributeIntroductionAspect(
new ObjectConstruction(typeof(NewMethodName).GetConstructor(new Type[] { typeof(string) }), new object[] { newName })
);

return new AspectInstance(target, x);
}
}

AOP Postsharp - Aspect attributes not working

I figured it out after hard trying. When we want to use Postsharp on our project, we must add Postsharp VS extension. After installing postsharp extension, we must logon and check our postsharp policy to target our classes with postsharp attributes (or custom derived postsharp attributes).
Postsharp provide 10 target class for express edition. After compile check out for output for postsharp process, if it succeed, postsharp inject IL code to our method that we marked with aspect attributes.
If we did everything right, we can get sessions,users etc everything can be logged without any workaround also provide dead easy caching mechanism.

Its all about postsharp VS Extension & Policy settings.

Possible to inject dynamic code using PostSharp AOP

The answer is no for the described use case. PostSharp runs after the C# compilation has already completed and processes the binary assembly. At this point it's already too late to add a string input for C# compiler.

Native PostSharp attributes are ignored if injected using Custom Attributes

You can provide DependencyPropertyAttribute directly as an aspect to the target property instead of going via CustomAttributeIntroductionAspect. For example:

yield return new AspectInstance(targetElement: property, aspect: new DependencyPropertyAttribute());

This is why DependencyPropertyAttribute is not processed when introduced as an attribute:

PostSharp pipeline processes the assembly in several phases. The processing of the attributes is executed first, after that the aspect weavers are executed. If any aspect is emitting a new custom attribute during this phase, the attribute will not be processed by PostSharp anymore because the attribute processing phase has already completed.

PostSharp injecting dependency to aspect

This kind of thing is not possible mainly because attributes in general and aspects in particular can only have constant expressions in the constructor.

The constructor is called once per aspected target during compilation time. After this happens, the aspect is serialized (along with any internal data it may contain). It is deserialized during runtime, which means the constructor is not called at all. But there is no reason for it to be called; attribute constructors can only contain constant data that isn't liable to change. See about aspect lifetime here.

However, every aspected target still has its own instance of the aspect. This means you can do this during runtime initialization. You have a few options:

  1. Supply a string key parameter to the constructor, and then during runtime look up the appropriate object using the key (from a shared dictionary).
  2. Rely on the aspected type to have a property or field containing the object, and access it through reflection. It's recommended you do this during runtime initialization because reflection can cause performance problems.

How do I add arguments to PostSharp attributes?

Just declare a property


[Serializable]
public class MethodLoggingAttribute : OnMethodBoundaryAspect
{
private ILog _logger;
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
_logger = LogManager.GetLogger(eventArgs.Method.DeclaringType.ToString());
if(ShowParameters = true)
{
_logger.DebugFormat("Entered {0} with args:{1}", eventArgs.Method.Name, args);
}
else
{
_logger.DebugFormat("Entered {0}", eventArgs.Method.Name);
}
}

private bool m_ShowParameters;

public bool ShowParameters
{
get { return m_ShowParameters; }
set { m_ShowParameters = value; }
}
}

Then you can specify it in the way you have mentioned.



Related Topics



Leave a reply



Submit