Not so long ago, I wrote concerning my interest in an AOP framework for .NET: PostSharp. Wasn’t a terribly interesting entry; such shallow meanderings have no place here! Let us correct that by delving into something a bit more interesting and dangerous.

Just a bit of a disclaimer up front:

PostSharp’s public API is fairly well documented; if you are reading this in hopes of learning about the basic and accepted uses of PostSharp, you probably want to go somewhere else. What I’m going to be writing about in this article are things that aren’t supported by the company that publishes PostSharp. As such, implementing any of the techniques or bits of code provided here into your company’s production software may be very dangerous for the overall stability of the software. Or, maybe it won’t be. That’s for you to decide.

The Problem

By far the most abundant type of data validation that occurs in your code is likely simple parameter checking for public methods. These exposed and invocable endpoints into our application need to be protected from this dangerous world; one must judiciously evaluate properness in the values passed to their methods as parameters, or else much embarrassment may be had should any trouble maker decide to lazily (or perhaps contemptuously!) string up a bunch of nulls and throw them your way.

Why, here comes a public method our way right now to serve as a demonstration of this rudimentary concept:

    public bool Process(CreditCard card, int csv)
    {
    	if (card.Brand == CreditCardBrands.MasterCard)
    	{
    		// MasterCard? Denied!!!
    		return false;
    	}

  	  return Process(card.Number, csv);
    }

Ah, a highly secure credit card processing function. We’ll probably want to check if the supplied instance of CreditCard is null or not, and then throw an ArgumentNullException for the card parameter if it turns out to be null. Otherwise, we’re bound to get a lovelyNullReferenceException if ever a null value is passed in.

This is important, as the last thing we ever want to see regurgitated from our code is a NullReferenceException, which itself is basically Microsoft’s fun little way of telling you or the people using your software that you suck.

The Typical Approach

Checking if a parameter is null isn’t rocket science. I’m rather loath to provide an example for this, but let’s do so for the sake of consistency:

    public bool Process(CreditCard card, int csv)
    {
    	if (null == card)
    		throw new ArgumentNullException("card", "Attempted to process null card.");

    	if (card.Brand == CreditCardBrands.MasterCard)
    	{
    		// MasterCard? Denied!!!
    		return false;
    	}

        return Process(card.Number, csv);
    }

That’s it. Although…I really hate magic strings, and the parameter name string that we provide to the ArgumentNullException cannot be guaranteed at compile-time to be correct. Heck, let’s address that.

    public bool Process(CreditCard card, int csv)
    {
        if (null == card)
        {
            throw new ArgumentNullException(ExpressionReader.ReadName(() => card),
                                            "Attempted to process null card.");
        }

        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number, csv);
    }

Ah wonderful, we’ve made use of a class that takes an Expression (in this case, a MemberExpression) and returns a name guaranteed to be accurate in case any wild refactoring binges occur.

We could go home right now, resign, and sleep contently. But, you and I, we don’t roll like that. We might have to do this type of check tens of thousands of times. This kind of manual labor doesn’t please the likes of us at all. Let’s correct this situation.

The (Typical) PostSharp Approach

Using the public and well-documented API of PostSharp, we can easily streamline this whole process so that we can our simple parameter validations declaratively. We just need to create and apply the appropriate aspects, and then we can watch the magic flow.

First off though, let’s ask ourselves: what do we want? Well, I think we can all agree that we want some sort of aspect that will validate a parameter for us in some way. A better question: how do we want to use it? The first thing that came to my mind in regards to what its usage would look like ideally was something like the following:

    public bool Process([NotNull]CreditCard card, int csv)
    {
        if (null == card)
            throw new ArgumentNullException("card", "Attempted to process null card.");

        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number, csv);
    }

Hmm. That would be pretty cool. It would allow me to mark exactly which parameters I wanted to validate, and how I wanted to validate them. In this instance, I only want to check if the credit card object is null, not the integer. Being that an integer is a value type, doing so would make me an idiot!

How do we want the aspect to behave? Well, we would probably want it to perform its validation operation prior to entering the body of the method, and we would want it to throw an ArgumentNullException (providing it the correct parameter name of course) if the parameter failed validation.

If you look at other articles online talking about how one goes about performing parameter validation (at least at the time of this article being written), you probably will run into many solutions that look similar to the preceding code snippet. Similar, but not identical. Instead, you’re going to find that almost all of the proposed solutions (that are more or less correct) are going to look like something like the following:

    [ValidateParameters]
    public bool Process([NotNull]CreditCard card)
    {
        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number);
    }

An extra attribute rests at the top of the method. Not perfect, but not too bad either. The reason why you are going to see this as the proposed solution is because, as I understand it, our ideal solution isn’t possible using just the built-in aspects of PostSharp (I am quite new to PostSharp myself, so…please inform me if I’m mistaken!).

One shouldn’t view this as a deficiency as far as PostSharp is concerned; indeed, our ideal solution just doesn’t make much sense even given how PostSharp seems to be designed (in regards to how we use it with the built-in aspects made available). Let’s rethink what we want with our heads buried in the reality of the actual framework.

If we think back to how we wanted this to behave, we wanted the validation to occur right before entering the body of the method. That alone would seem to imply that we want to be operating on the method level.

Certainly, the method itself would need to be changed in order to realize this requirement. It follows then that we would want to use something like the OnMethodBoundaryAspect aspect as our base. Let’s name our base ValidateParametersAttribute. For the actual attributes that perform the validation on the parameters, these will actually not be aspects. They will, however, be all passed on a commonParameterValidationAttribute class.

ValidateParametersAttribute

Our ValidateParametersAttribute aspect should do the following:

  1. During build-time, the ValidateParametersAttribute should cache information for all of the parameters so we can avoid this costly operation at run-time.
  2. Among the information cached should be the various ParameterValidationAttribute attribute instances decorating the method’s parameters.
  3. At run-time, our aspect should make use of the stored ParameterValidationAttribute instances in order to perform validation checks on the method’s parameters every time the method is executed.

Here’s what it would look like:

    /// <summary>
    /// Provides an aspect used to signal that the decorated method supports attribute-specified
    /// validation on one or more of its parameters. This class cannot be inherited.
    /// </summary>
    [Serializable]
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)]
    [ProvideAspectRole(StandardRoles.Validation)]
    [AspectRoleDependency(
        AspectDependencyAction.Order, AspectDependencyPosition.After, StandardRoles.Tracing)]
    public sealed class ValidateParametersAttribute : OnMethodBoundaryAspect
    {
        private readonly List<ParameterInfo> _parameterMap = new List<ParameterInfo>();

        private readonly Dictionary<int, List<ParameterValidationAttribute>> _validationMap
            = new Dictionary<int, List<ParameterValidationAttribute>>();

        /// <summary>
        /// Method invoked at build-time to build the parameter mapping information stored for later
        /// use by this aspect.
        /// </summary>
        /// <param name="method">Method to which this aspect is applied.</param>
        /// <param name="aspectInfo">Reserved parameter.</param>
        public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
        {
            if (null == method)
                throw new ArgumentNullException("method", Strings.ErrorCompileTimeInitializeNull);

            base.CompileTimeInitialize(method, aspectInfo);

            ParameterInfo[] parameters = method.GetParameters();

            for (int i = 0; i < parameters.Length; i++)
            {
                _parameterMap.Add(parameters[i]);

                IEnumerable<ParameterValidationAttribute> validationAttributes
                  = parameters[i].GetCustomAttributes(false).OfType<ParameterValidationAttribute>();

                foreach (ParameterValidationAttribute validationAttribute in validationAttributes)
                  MapAttribute(i, validationAttribute);
            }
        }

        /// <summary>
        /// Method executed prior to the applied method's execution.
        /// </summary>
        /// <param name="args">
        /// Arguments specifying which method is being executed, information regarding the method's
        /// arguments, and the flow of execution.
        /// </param>
        public override void OnEntry(MethodExecutionArgs args)
        {
            if (null == args)
                throw new ArgumentNullException("args", Strings.ErrorOnEntryNullArgs);

            for (int i = 0; i < args.Arguments.Count; i++)
            {
                if (!_validationMap.ContainsKey(i))
                    continue;

                foreach (ParameterValidationAttribute validationAttribute in _validationMap[i])
                {
                    validationAttribute.ValidateParameter(args.Method.Name,
                                                          _parameterMap[i],
                                                          args.Arguments[i]);
                }
            }

            base.OnEntry(args);
        }

        /// <summary>
        /// Maps the provided <see cref="ParameterValidationAttribute"/> object to the specified
        /// key.
        /// </summary>
        /// <param name="key">
        /// The key to associate with the <see cref="ParameterValidationAttribute"/> object.
        /// </param>
        /// <param name="validationAttribute">The validation attribute to map.</param>
        private void MapAttribute(int key, ParameterValidationAttribute validationAttribute)
        {
            if (!_validationMap.ContainsKey(key))
                _validationMap.Add(key, new List<ParameterValidationAttribute>());

            List<ParameterValidationAttribute> attributeList = _validationMap[key];

            attributeList.Add(validationAttribute);
        }
    }

Pretty simple.

ParameterValidationAttribute

Let’s take a look, then, at our ParameterValidationAttribute base class:

    /// <summary>
    /// Provides a custom attribute that performs a type of validation on
    /// the decorated parameter on the behalf of an aspect. This class is abstract.
    /// </summary>
    [Serializable]
    [AttributeUsage(AttributeTargets.Parameter)]
    public abstract class ParameterValidationAttribute : Attribute
    {
        /// <summary>
        /// Performs validation on the object provided, throwing an exception if validation fails.
        /// </summary>
        /// <param name="methodName">The name of the method the parameter belongs to.</param>
        /// <param name="parameterInfo">
        /// The <see cref="ParameterInfo"/> of the decorated parameter.
        /// </param>
        /// <param name="value">An instance of the decorated parameter.</param>
        public abstract void ValidateParameter(
            string methodName, ParameterInfo parameterInfo, object value);
    }

Ouch. Even simpler!

NotNullAttribute

Finally, let’s take a look at our example implementation of the ParameterValidationAttribute type, which will check if the decorated parameter is null:

    /// <summary>
    /// Provides a custom attribute that performs validation ensuring that the decorated parameter's
    /// value is not null. This class cannot be inherited.
    /// </summary>
    [Serializable]
    [AttributeUsage(AttributeTargets.Parameter)]
    public sealed class NotNullAttribute : ParameterValidationAttribute
    {
        /// <inheritdoc/>
        public override void ValidateParameter(
            string methodName, ParameterInfo parameterInfo, object value)
        {
            if (null == parameterInfo)
            {
                throw new ArgumentNullException("parameterInfo",
                                                Strings.ErrorValidateParameterNullInfo);
            }

            if (null == value)
            {
                throw new ArgumentException(parameterInfo.Name,
                                            String.Format(CultureInfo.InvariantCulture,
                                                          Strings.ErrorIsNotNullFailed,
                                                          parameterInfo.Name,
                                                          methodName));
            }
        }
    }

And there you have it. This approach meets our requirements, and offers us a lot of room for adding additional types of validation checks on the parameters.

Needs More Cowbell, Matt.

For some of the…more special types among us, that may still not be enough. Certainly, the above information doesn’t justify this article. As stated earlier, there are well known examples online that would have led you down the same path.

How could we improve this? Well, if we look back to the near beginning of this article, we’ll see our initial idea which we concluded wasn’t possible:

    public bool Process([NotNull]CreditCard card, int csv)
    {
        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number, csv);
    }

Specifically, we wanted to be able to simply apply an attribute to the parameter and be done with it. It wasn’t our initial goal to have to be required to also decorate the method with an attribute.

I wasn’t lying when I said this isn’t possible using the built-in PostSharp aspects. But, it is indeed possible if we extend PostSharp. I’m going to show you how to do that.

The (Not-So-Typical) PostSharp Approach

In addition to using PostSharp’s built-in aspects to perform parameter validation, we can also extend PostSharp so that we can perform the validation in a way that is more to our liking.

Just to re-iterate, our goal is to be able to validate parameters like so:

    public bool Process([NotNull]CreditCard card, int csv)
    {
        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number, csv);
    }

That is, we want to be able to perform parameter validation simply by decorating the parameters we want to validate. The attribute used to decorate the parameter should be an independent validation unit, whose presence alone will result in the necessary instructions being injected that will cause the parameter to be validated upon execution of the method.

Using the built-in aspects, we were able to realize parameter validation through the use of a method boundary aspect that would iterate through and execute the various special parameter validation attributes found on its parameters. There doesn’t seem to be a way to perform validation in the way we’re going to do it using built-in aspects, mainly because the built-in aspects are all meant to be general purpose, and having a general purpose parameter aspect that would go off upon method execution wouldn’t make any sense.

In order to implement functioning independent parameter validation attributes, we’re going to have to make use of the PostSharp SDK and manually weave the appropriate MSIL into our code. We also have to create a number of validation aspects that will ultimately be used to provide this type of validation. Before we get into the SDK, then, let’s look at the validation aspects that will support what we want to do.

Note: The code snippets found in the following sections are meant to show you the crucial actions that must be taken in order to integrate the functionality described by this article into your solution. There will be some things referenced (like resource strings) that aren’t going to compile for you. These snippets are meant to demonstrate, not for you to copy ‘n paste.

Validation Aspects

If you’re like me, then you may have a general-purpose aspects framework/library featuring custom aspects that get used across the products you publish. Although the entities constituting our little “validation framework”, as you’ll see, aren’t derivations of built-in PostSharp aspects, our general-purpose aspects framework/library is a good enough home for them.

The core of the framework is made up of the following attributes:

  • ValidationAttributeA base aspect used to perform some kind of validation on the decorated code element.
  • ParameterValidationAttributeA base aspect used to perform some kind of validation on the decorated parameter.
  • MethodValidationAttributeA base aspect used to perform some kind of validation on all the parameters belonging to the decorated method. This particular family of validation aspects isn’t covered in this article.

The ValidationAttribute class provides the core infrastructure for useful validation, and both the ParameterValidationAttribute andMethodValidationAttribute types derived from it.

Although I’ve just described these types as aspects that will perform some magic on the applied code elements at compile-time, you may find yourself disagreeing with this assertion after looking at the code behind each one.

In fact, you’d be (mostly) correct in saying that they appear to only be simple attributes, and nothing more. Indeed, left by themselves, PostSharp would have nothing to do with them come compile-time, and they’d be very useless!

ValidationAttribute

The ValidationAttribute type is an abstract class serving as the foundation for all validation aspects; it offers compile-time validation, the ability to set the exception type and message should validation fail, and some support functionality to be used by deriving aspects.

ValidationAttribute.cs

    /// <summary>
    /// Provides a base aspect used to perform some kind of validation on the decorated code
    /// element.
    /// </summary>
    [Serializable]
    [RequirePostSharp("Omniscientist.AspectWeaver", "ValidationProcessor")]
    public abstract class ValidationAttribute : Attribute
    {
        /// <summary>
        /// Gets or sets the type of <see cref="System.Exception"/> thrown upon validation failure.
        /// </summary>
        public Type Exception
        { get; set; }

        /// <summary>
        /// Gets or sets the message used when throwing an exception upon validation failure.
        /// </summary>
        public string FailureMessage
        { get; set; }

        /// <summary>
        /// Gets the validation method responsible for validating the method the advice is
        /// applied to.
        /// </summary>
        public abstract MethodBase ValidationMethod { get; }

        /// <summary>
        /// Method invoked at build-time to ensure that the target this advice is applied to is
        /// an appropriate one.
        /// </summary>
        /// <param name="metadata">Metadata for the parameter receiving the advice.</param>
        /// <param name="typeValidated">The type of object ultimately being validated.</param>
        /// <param name="messages">
        /// An <see cref="IMessageSink"/> instance, used to write messages.
        /// </param>
        [CLSCompliant(false)]
        public virtual void CompileTimeValidate(
            INamedMetadataDeclaration metadata, Type typeValidated, IMessageSink messages)
        {
            // Usually I don't throw exceptions in aspect methods that are active at compile-time,
            // but this takes the cake...
            if (null == messages)
                throw new ArgumentNullException("messages", Strings.ValidationNullMessageSink);

            if (!ValidateNonNullMetadata(metadata, messages))
                return;

            if (!ValidateExceptionType(messages))
                return;

            if (!ValidateInitializableExceptionType(messages))
                return;

            messages.Write(
                new Message(MessageLocation.Of(metadata),
                            SeverityType.Verbose,
                            Strings.ValidationAspectPassedValidationMessageId,
                            String.Format(CultureInfo.InvariantCulture,
                                          Strings.ValidationAspectPassedValidationMessageFormat,
                                          metadata.Name),
                            String.Empty,
                            Assembly.GetCallingAssembly().FullName,
                            null));
        }

        /// <summary>
        /// Deserializes an object from the specified string.
        /// </summary>
        /// <param name="serializedValue">The serialized object.</param>
        /// <returns></returns>
        public static object DeserializeFromString(string serializedValue)
        {
          BinaryFormatter formatter = new BinaryFormatter();

          using (MemoryStream buffer = new MemoryStream(Convert.FromBase64String(serializedValue)))
          {
              return formatter.Deserialize(buffer);
          }
        }

        /// <summary>
        /// Handles the response to a failure in validation of the applied element by throwing
        /// the configured type of exception.
        /// </summary>
        /// <param name="message">
        /// A message to use when throwing the exception. This is ignored if the current
        /// <see cref="ValidationAttribute"/> is configured to use a standard validation error
        /// message.
        /// </param>
        /// <param name="exception">
        /// The type of exception to throw (ignoring the configured type).
        /// </param>
        protected void ValidationFailed(string message, Type exception = null)
        {
            Type exceptionType = exception ?? Exception;

            string errorMessage = String.IsNullOrEmpty(FailureMessage) ? message : FailureMessage;

            // If no exception has been configured, we'll just fallback to a "stock" type.
            // InvalidOperationException fits pretty much any situation, if a bit unclear.
            if (null == exceptionType)
                throw new InvalidOperationException(errorMessage);

            throw (Exception)Activator.CreateInstance(exceptionType, errorMessage);
        }

        /// <summary>
        /// Handles the response to a failure in validation of the applied element by throwing the
        /// configured type of exception.
        /// </summary>
        /// <param name="message">
        /// A message to use when throwing the exception. This is ignored if the current
        /// <see cref="ParameterValidationAttribute"/> is configured to use a standard validation
        /// error message.
        /// </param>
        /// <param name="elementValue">The value of the element that failed validation.</param>
        /// <param name="elementName">The name of the element that failed validation.</param>
        /// <param name="exception">
        /// The type of exception to throw (ignoring the configured type).
        /// </param>
        protected void ValidationFailed(
            string message, object elementValue, string elementName, Type exception = null)
        {
            Type exceptionType = exception ?? Exception;

            string errorMessage = String.IsNullOrEmpty(FailureMessage) ? message : FailureMessage;

            // If no exception has been configured, we'll just fallback to a "stock" type.
            // InvalidOperationException fits pretty much any situation, if a bit unclear.
            if (null == exceptionType)
                throw new InvalidOperationException(errorMessage);

            // We'll make an attempt to tap into some built-in functionality of some well-known
            // types in the event one of them is the configured exception type.
            if (typeof(ArgumentNullException).Equals(exceptionType))
                throw new ArgumentNullException(elementName, message);

            if (typeof(ArgumentException).Equals(exceptionType))
                throw new ArgumentException(message, elementName);

            if (typeof(ArgumentOutOfRangeException).Equals(exceptionType))
                throw new ArgumentOutOfRangeException(elementName, elementValue, message);

            throw (Exception)Activator.CreateInstance(exceptionType, errorMessage);
        }

        /// <summary>
        /// Validates that the configured exception <see cref="Type"/> is an actual type of
        /// <see cref="System.Exception"/>.
        /// </summary>
        /// <param name="messages">
        /// An <see cref="IMessageSink"/> instance, used to write messages.
        /// </param>
        /// <returns>
        /// True if <see cref="Exception"/> is a valid type of exception; otherwise, false.
        /// </returns>
        private bool ValidateExceptionType(IMessageSink messages)
        {
            bool isException = null != Exception && typeof (Exception).IsAssignableFrom(Exception);

            if (!isException)
            {
                messages.Write(
                    new Message(MessageLocation.Of(Exception),
                                SeverityType.Fatal,
                                Strings.ErrorValidationExceptionBadTypeMessageId,
                                String.Format(CultureInfo.InvariantCulture,
                                              Strings.ErrorValidationExceptionBadTypeMessageFormat,
                                              Exception.Name),
                                String.Empty,
                                Assembly.GetCallingAssembly().FullName,
                                null));
            }

            return isException;
        }

        /// <summary>
        /// Validates that the configured validation failure exception is able to be initialized
        /// by the aspect.
        /// </summary>
        /// <param name="messages">
        /// An <see cref="IMessageSink"/> instance, used to write messages.
        /// </param>
        /// <returns>
        /// True if the configured exception can be instantiated by this aspect; otherwise, false.
        /// </returns>
        /// <remarks>
        /// A properly implemented exception will additionally declare constructors that match the
        /// signatures of the base see cref="Exception"/> type. This aspect relies particularly on
        /// the presence of a constructor overload that accepts a single string parameter (the
        /// exception message).
        /// </remarks>
        private bool ValidateInitializableExceptionType(IMessageSink messages)
        {
            ConstructorInfo constructor
                = Exception.GetConstructor(BindingFlags.Public | BindingFlags.Instance,
                                           null,
                                           new[] { typeof(string) },
                                           null);

            bool isInstantiable = null != constructor;

            if (!isInstantiable)
            {
                messages.Write(
                    new Message(MessageLocation.Of(Exception),
                                SeverityType.Fatal,
                                Strings.ErrorValidationExceptionImproperTypeMessageId,
                                String.Format(CultureInfo.InvariantCulture,
                                              Strings.ErrorValidationExceptionImproperTypeMessage,
                                              Exception.Name),
                                String.Empty,
                                Assembly.GetCallingAssembly().FullName,
                                null));
            }

            return isInstantiable;
        }

        /// <summary>
        /// Validates that the provided metadata is not null.
        /// </summary>
        /// <param name="metadata">The metadata to do a null check on.</param>
        /// <param name="messages">
        /// An <see cref="IMessageSink"/> instance, used to write messages.
        /// </param>
        /// <returns>True if <c>metadata</c> is not null; otherwise, false.</returns>
        private static bool ValidateNonNullMetadata(
            INamedMetadataDeclaration metadata, IMessageSink messages)
        {
            bool isNotNull = null != metadata;

            if (!isNotNull)
            {
                messages.Write(
                    new Message(MessageLocation.Of(metadata),
                                SeverityType.Fatal,
                                Strings.ErrorNullMetadataMessageId,
                                Strings.ErrorNullMetadataMessage,
                                String.Empty,
                                Assembly.GetCallingAssembly().FullName,
                                null));
            }

            return isNotNull;
        }
    }

The majority of the code above should be self-explanatory. The only thing I’ll say is that the oddly public and seemingly out-of-place “DeserializeString” is an essential component that is used by our PostSharp extension. We’ll get more into why it is there and what it does later — the important thing is that it really needs to be public and static. It could be in a utility class instead, if that floats your boat, but it is very easy for things to get a bit more complicated than it is worth in this instance. More on that later.

So far all we have is a pretty normal (well, maybe not so normal) attribute; how is the above in any way an “aspect”?

If you look at the class signature itself, you’ll see an all-important attribute: RequiresPostSharp. Ahh, there’s our hook. By applying this attribute, we’re telling PostSharp to perform some further processing on entities decorated with this or any deriving attribute.

Now of course, PostSharp won’t have any idea how to “process” this attribute. Thus, we need to actually provide an extension to PostSharp in order for anything to actually get done. The arguments we pass to the RequiresPostSharp attribute’s constructor essentially wire PostSharp up to our extension.

The first argument is the name of our PostSharp plugin DLL, minus the “.dll”. The second argument is the name of the specific “Task” which will do the processing. We’ll take a look at how to make this plugin DLL in the Extending Postsharp section.

ParameterValidationAttribute

The ParameterValidationAttribute type is the foundation for all parameter-specific validation aspects. All concrete validation aspects must derive from it in order to be used in a way aligned with the type of usage we determined earlier to be ideal.

ParameterValidationAttribute.cs

    /// <summary>
    /// Provides a base aspect used to perform some kind of validation on the decorated parameter.
    /// This class is abstract.
    /// </summary>
    [Serializable]
    [AttributeUsage(
        AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple=true, Inherited=true)]
    public abstract class ParameterValidationAttribute : ValidationAttribute
    {
        /// <inheritdoc/>
        public override MethodBase ValidationMethod
        {
            get { return ReadMethodBase((x,y,z) => Validate(x,y,z)); }
        }

        /// <summary>
        /// Gets the name of the method that the parameter of interest belongs to.
        /// </summary>
        protected string MethodName
        { get; private set; }

        /// <inheritdoc/>
        [CLSCompliant(false)]
        public override void CompileTimeValidate(
            INamedMetadataDeclaration metadata, Type typeValidated, IMessageSink messages)
        {
            base.CompileTimeValidate(metadata, typeValidated, messages);

            MethodName = metadata.ParentMember.Name;
        }

        /// <summary>
        /// Executes the validation logic associated with this aspect.
        /// </summary>
        /// <param name="target">
        /// An instance of the object hosting the parameter on which the validation method is
        /// being invoked.
        /// </param>
        /// <param name="value">The value of the parameter being validated.</param>
        /// <param name="parameterName">The name of the parameter being validated.</param>
        /// <remarks>
        /// This needs to remain public, even if it appears it has no external callers. This method
        /// is invoked in a non-standard way by some MSIL added by our aspect weaver.
        /// </remarks>
        public abstract void Validate(object target, object value, string parameterName);

        /// <summary>
        /// Retrieves the <see cref="MethodBase"/> of the method expressed.
        /// </summary>
        /// <param name="methodExpression">An expression of the method being called.</param>
        /// <returns>
        /// Information regarding the method expressed in <c>methodExpression</c>.
        /// </returns>
        private static MethodBase ReadMethodBase(
            Expression<Action<object,object,string>> methodExpression)
        {
            MethodCallExpression method = (MethodCallExpression) methodExpression.Body;

            return method.Method;
        }
    }

And there’s the foundation for all parameter-specific validation aspects. Yes, the foundation; we’re stealing in abstract classes here. Let’s finish off with an actually usable concrete validation aspect.

NotNullAttribute

Let’s take a look at the concrete NotNullAttribute type. This attribute would be applied to a parameter in a manner identical to the example usage shown at the start of this “not-so-typical” approach:

    public bool Process([NotNull]CreditCard card, int csv)
    {
        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number, csv);
    }

You’ll get an idea as to how simple it will be to add additional validation attributes using this approach.

NotNullAttribute.cs

    /// <summary>
    /// Provides a validation attribute that, when applied to a parameter, will ensure that the
    /// parameter is not null.
    /// </summary>
    [Serializable]
    [AttributeUsage(
        AttributeTargets.Parameter | AttributeTargets.Property,AllowMultiple=true,Inherited=true)]
    public sealed class NotNullAttribute : ParameterValidationAttribute
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="NotNullAttribute"/> class.
        /// </summary>
        /// <remarks>
        /// The default exception type set by the constructor is
        /// <see cref="ArgumentNullException"/>.
        /// </remarks>
        public NotNullAttribute()
        {
            Exception = typeof (ArgumentNullException);
        }

        /// <inheritdoc/>
        [CLSCompliant(false)]
        public override void CompileTimeValidate(
            INamedMetadataDeclaration metadata, Type typeValidated, IMessageSink messages)
        {
            base.CompileTimeValidate(metadata, typeValidated, messages);

            if (typeValidated.IsValueType && null == Nullable.GetUnderlyingType(typeValidated))
            {
                messages.Write(
                    new Message(MessageLocation.Of(metadata),
                                SeverityType.Error,
                                Strings.ErrorNotNullNonNullableMessageId,
                                String.Format(CultureInfo.InvariantCulture,
                                              Strings.ErrorNotNullNonNullableMessageFormat,
                                              typeValidated.Name),
                                String.Empty,
                                Assembly.GetCallingAssembly().FullName,
                                null));
            }
        }

        /// <inheritdoc/>
        public override void Validate(object target, object value, string parameterName)
        {
            if (null == value)
            {
                ValidationFailed(
                    String.Format(CultureInfo.InvariantCulture,
                                  Strings.ErrorIsNotNullFailedFormat,
                                  parameterName,
                                  MethodName),
                    value,
                    parameterName);
            }
        }
    }

As you can see here, by overriding the Validate method, we can easily inject the specific type of validation provided by the particular validation aspect.

Well, the above is all well and good. Certainly makes me salivate just looking at it; but, it is all useless without the extension to PostSharp. Let’s jump into that now.

Extending PostSharp

Let me preface by saying once again that the rest of this article deals with items that lack documentation — the code presented was garnered through my own research and some trial-and-error. Although it works and provides the promised functionality, I’m making no claim or guarantee of absolute correctness.

In order to make the magic promised by the above validation aspects a reality, we need to get down and dirty with PostSharp by providing our own extension to it. The specific extension, in a sense, is our own special kind of aspect weaver.

Our extension takes the form of an assembly named “Omniscientist.AspectWeaver.dll”, which itself is produced in a project separate from the one housing our aspects. The link to this particular DLL was established by decorating our base validation aspect (ValidationAttribute) with theRequiresPostSharp attribute. Using this attribute, we explicitly spelled out the name of our extension and the task to use.

But this, in itself, is not sufficient in getting PostSharp to use our plugin. Looking back at the RequiresPostSharp attribute, we see that the second argument we give it is the name of our task. The particular entity we’re naming here, in actuality, isn’t any particular class in code, but rather an entity defined in a PostSharp-specific config file that needs to be provided with the aspect weaver.

Plugin Configuration (.psplugin)

This configuration file should be named after the assembly itself, and should end in “.psplugin”. For our aspect weaver, we have the following:

Omniscientist.AspectWeaver.psplugin

    <?xml version="1.0" encoding="utf-8" ?>
    <PlugIn xmlns="http://schemas.postsharp.org/1.0/configuration">
      <TaskType Name="ValidationProcessor"
                Implementation="Omniscientist.AspectWeaver.ValidationProcessorTask, Omniscientist.AspectWeaver"
                Phase="Transform">
        <Dependency TaskType="CodeWeaver" Position="After"/>
      </TaskType>
    </PlugIn>

As you may have realized, the “Task” you are naming in the RequiresPostSharp declaration is a particular entry in the plugin configuration file. It is this entry, then, that maps this task to a particular class in code.

And because we’ve just identified that particular class that acts as the processing class, let’s start our foray into our custom aspect weaver by examining it.

ValidationProcessorTask

The ValidationProcessorTask class is the center of our custom aspect weaver. It is the organizer and executor of all the various post-compile weavings that our validation aspects require.

Our class, appropriately, derives from the Task type and implements the IAdviceProvider interface, both of which are found in thePostSharp.Sdk.dll assembly.

The reason IAdviceProvider is being implemented is so we will be handed a Weaver instance, which is PostSharp’s main weaver that lets us emit instructions in our code.

It also makes sense because the essence of what our extension does has to do with applying advices to our hollow aspects, making them whole.

You may notice that when you implement IAdviceProvider, that an “obsolete” warning will be thrown at us. Indeed, it appears thatIAdviceProvider is obsolete, and, according to the message provided with the warning, we should be creating an instance of Weaver locally within our task.

Although I’m sure this particular warning should be taken seriously, I could not figure out how to get a working solution when initializing theWeaver locally. It is easy enough to initialize, it just wouldn’t seem to actually do anything. I did not spend very much time on attempting to get that to work, so maybe you will have better luck.

Normally, I wouldn’t consider something complete with this type of warning, but, again, we’re dealing with some undocumented stuff here. In my case, I suppressed the warning with a #pragma, as I found it to be working just fine. If a newer version causes this extension to break severely, we’ll have an idea as to why…

ValidationProcessTask.cs

    /// <summary>
    /// Provides a PostSharp <see cref="Task"/> that applies advice that processes any validation
    /// attributes that decorate elements of our code.
    /// </summary>
    public class ValidationProcessorTask : Task, IAdviceProvider
    {
        private Weaver _codeWeaver;

        /// <summary>
        /// Entrypoint to this task which, in turn, triggers its execution.
        /// </summary>
        /// <param name="codeWeaver">The active code weaver, provided by PostSharp.</param>
        public void ProvideAdvices(Weaver codeWeaver)
        {
            _codeWeaver = codeWeaver;

            WeaveMethods();
            WeaveProperties();
        }

        /// <summary>
        /// Weaves validation advice for all the applicable parameter and method declarations
        /// found in the current assembly.
        /// </summary>
        private void WeaveMethods()
        {
            foreach (MethodDefDeclaration method in EnumerateMethods())
            {
                for (int i = 0; i < method.Parameters.Count; i++)
                    ApplyParameterAdvice(method.Parameters[i], method, i);

                ApplyMethodAdvice(method);
            }
        }

        /// <summary>
        /// Weaves validation advice for all the applicable property declarations found in the
        /// current assembly.
        /// </summary>
        private void WeaveProperties()
        {
            foreach (PropertyDeclaration property in EnumerateProperties())
                ApplyPropertyAdvice(property);
        }

        /// <summary>
        /// Creates and applies parameter validation advice for all parameters validation
        /// attributes found in provided parameter declaration.
        /// </summary>
        /// <param name="target">
        /// Parameter declaration that may contain one or more validation attributes.
        /// </param>
        /// <param name="method">
        /// The method that the parameter belongs to.
        /// </param>
        /// <param name="parameterIndex">
        /// The index of the parameter in the method's argument list.
        /// </param>
        private void ApplyParameterAdvice(
            ParameterDeclaration target, MethodDefDeclaration method, int parameterIndex)
        {
            IEnumerable<ParameterValidationAdvice> advices
                = FindAdvisableAttributes<ParameterValidationAttribute>(target)
                    .Select(x => new ParameterValidationAdvice(x, target, parameterIndex));

            foreach (ParameterValidationAdvice advice in advices)
                ApplyAdvice(advice, method);
        }

        /// <summary>
        /// Creates and applies parameter validation advice for all parameter validation
        /// attributes found in the provided property declaration.
        /// </summary>
        /// <param name="target">The property declaration to apply the advice to.</param>
        private void ApplyPropertyAdvice(PropertyDeclaration target)
        {
            if (!target.CanWrite)
                return;

            MethodDefDeclaration method
                = target.Members.GetBySemantic(MethodSemantics.Setter).Method;

            IEnumerable<ParameterValidationAdvice> advices
                = FindAdvisableAttributes<ParameterValidationAttribute>(target)
                    .Select(x => new ParameterValidationAdvice(x, method.Parameters[0], 0));

            foreach (ParameterValidationAdvice advice in advices)
                ApplyAdvice(advice, method);
        }

        /// <summary>
        /// Creates and applies method validation advice for all method validation attributes
        /// found in the provided method declaration.
        /// </summary>
        /// <param name="target">The method declaration to apply the advice to.</param>
        private void ApplyMethodAdvice(MethodDefDeclaration target)
        {
            IEnumerable<CustomAttributeDeclaration> attributes
                = FindAdvisableAttributes<MethodValidationAttribute>(target);

            foreach (CustomAttributeDeclaration attribute in attributes)
            {
                CollectParametersAdvice parametersAdvice = new CollectParametersAdvice(target);
                MethodValidationAdvice methodAdvice = new MethodValidationAdvice(attribute);

                ApplyAdvice(parametersAdvice, target);
                ApplyAdvice(methodAdvice, target);
            }
        }

        /// <summary>
        /// Applies the provided advice to the specified method.
        /// </summary>
        /// <param name="advice">Advice to apply to <c>method</c>.</param>
        /// <param name="method">The method declaration the advice gets applied to.</param>
        private void ApplyAdvice(IAdvice advice, MethodDefDeclaration method)
        {
            _codeWeaver.AddMethodLevelAdvice(
                advice, new[] { method }, JoinPointKinds.BeforeMethodBody, null);
            _codeWeaver.AddTypeLevelAdvice(
                advice, JoinPointKinds.BeforeStaticConstructor, new[] { method.DeclaringType });
        }

        /// <summary>
        /// Applies the provided advice to the specified method.
        /// </summary>
        /// <param name="advice">
        /// Advice responsible for creating parameter name/value pairs for <c>method</c>.
        /// </param>
        /// <param name="method">The method declaration the advice gets applied to.</param>
        private void ApplyAdvice(CollectParametersAdvice advice, MethodDefDeclaration method)
        {
            _codeWeaver.AddMethodLevelAdvice(
                advice, new[] {method}, JoinPointKinds.BeforeMethodBody, null);
        }

        /// <summary>
        /// Exposes an enumerator for the various <see cref="MethodDefDeclaration"/> instances
        /// found in the current assembly.
        /// </summary>
        /// <returns>
        /// An exposed enumerator which supports the iteration over a collection of
        /// <see cref="MethodDefDeclaration"/> objects.
        /// </returns>
        private IEnumerable<MetadataDeclaration> EnumerateMethods()
        {
            IEnumerator<MetadataDeclaration> methodEnumerator
                = Project.Module.GetDeclarationEnumerator(TokenType.MethodDef);

            return Enumerate(methodEnumerator);
        }

        /// <summary>
        /// Exposes an enumerator for the various <see cref="PropertyDeclaration"/> instances found
        /// in the current assembly.
        /// </summary>
        /// <returns>
        /// An exposed enumerator which supports the iteration over a collection of
        /// <see cref="PropertyDeclaration"/> objects.
        /// </returns>
        private IEnumerable<MetadataDeclaration> EnumerateProperties()
        {
            IEnumerator<MetadataDeclaration> propertyEnumerator =
                Project.Module.GetDeclarationEnumerator(TokenType.Property);

            return Enumerate(propertyEnumerator);
        }

        /// <summary>
        /// Finds all <see cref="CustomAttributeDeclaration"/> belonging to the provided metadata
        /// that should be used to generate advice.
        /// </summary>
        /// <typeparam name="TValidationAttribute">
        /// The validation attribute type to look for.
        /// </typeparam>
        /// <param name="target">
        /// The metadata containing one or more validation attribute declarations.
        /// </param>
        /// <returns>
        /// Exposed enumerator supporting iteration over all validation attribute declarations
        /// that should be used to generate advice.
        /// </returns>
        private static IEnumerable<CustomAttributeDeclaration>
            FindAdvisableAttributes<TValidationAttribute>(IMetadataDeclaration target)
        {
           return from attribute in target.CustomAttributes
                  let attributeType = attribute.Constructor.DeclaringType.GetSystemType(null, null)
                  where typeof(TValidationAttribute).IsAssignableFrom(attributeType)
                  select attribute;
        }

        /// <summary>
        /// Exposes the provided enumerator.
        /// </summary>
        /// <typeparam name="T">The type of items in the enumerator.</typeparam>
        /// <param name="enumerator">
        /// Object which supports simple iteration over a generic collection.
        /// </param>
        /// <returns>
        /// An exposed enumerator that supports simple iteration over a generic collection.
        /// </returns>
        /// <remarks>
        /// For some reason PostSharp deals in returning <see cref="IEnumerator{T}"/> objects
        /// instead of the more common <see cref="IEnumerable{T}"/> type. This method exists
        /// to compensate for that.
        /// </remarks>
        private static IEnumerable<T> Enumerate<T>(IEnumerator<T> enumerator)
        {
            while (enumerator.MoveNext())
            {
                yield return enumerator.Current;
            }
        }
    }

I’ll let the documented pieces of code speak for themselves.

The only legitimate sources of confusion here should be the various initializations of element-specific advices, such as theParameterValidationAdvice and MethodValidationAdvice. These two advices relate to the ParameterValidationAttribute andMethodValidationAttribute aspects respectively.

These advices are the true meat of all of this; they provide the majority of the magic. We’re going to look at the parameter variant, but the method advice is going to be excluded from this article.

Parameter Validation Advice

We see various validation advices being initialized and applied to the declarations of our validation attributes in the processor code shown above.

These classes are where the actual weaving takes place. In my case, I was able to abstract a more general and element-neutral type of advice in a class named ValidationAdvice. The ParameterValidationAdvice and MethodValidationAdvice classes then derive from this. These classes are actual advice as well, as they implement the IAdvice interface, which is defined in PostSharp’s SDK.

While I’m sure we’d all love it if I simply provided the code for all of these classes, I’m not going to do this. Instead, I’m going to walk through what must be done by a parameter validation type of advice, and the relevant code snippets required in order to do it.

Note that I’m also going to include steps that are common to all types of validation advices, and not just one directed at parameters. You can identify these and abstract away at them as you see fit.

Initialization

As we can see in the above code for the processor, the parameter validation advice is initialized with a CustomAttributeDeclaration, aParameterDeclaration, and the index of the parameter within its containing method’s argument list.

The first thing I recommend doing is determining if the parameter being validated contains any generic arguments. More specifically, is the parameter an open (constructed or not) generic type? Examples of this are KeyValuePair<TKey,int> and IEnumerable. Closed constructed types do not meet this criterion.

If the parameter contains some type of generic argument or arguments, then you would do well to extract and store two separate Type arrays consisting of:

  1. All (if any) of the generic arguments of the method containing the parameter
  2. All (if any) of the generic arguments of the type containing the method containing the parameter

The reason you need to do the above relates to the origin of the parameter’s generic argument. The run-time will define the type behind the argument using a type provided for either the method or type.

Examples relating to the parameter types proposed above:

    public class SomeDictionary<TKey> {...}

    public class SomethingElse
    {
        public IEnumerable<T> SomeMethod<T>(IEnumerable<T> enumerable) {...}
    }

If you look at the ParameterDeclaration type that is provided during initialization, you’ll see (unless I missed something…) that it lacks actualSystem.Type information. In order to retrieve that information, you apparently need to call the GetSystemType method provided by the declaration.

This method takes two parameters, that being the type arrays of the method and type generic arguments. If you want to be able to get the Typeback for a parameter that is an open generic type, you have to supply these arrays, or you will fail.

This tripped me up for some time, until I looked at what I was doing a bit harder and figured it out.

In order to get the generic arguments from the method containing a ParameterDeclaration named parameter, you can use the following:

	Type[] genericMethodArguments = null;

	int methodGenericCount = parameter.DeclaringMethod.GenericParameters.Count;

	if (0 < methodGenericCount)
	{
		genericMethodArguments = new Type[methodGenericCount];

		for (int i = 0; i < methodGenericCount; i++)
		{
			genericMethodArguments[i]
                            = parameter.DeclaringMethod
                                .GenericParameters[i].GetSystemType(null, null);
		}
	}

	return genericMethodArguments;

To get the generic arguments for the type containing the method containing a ParameterDeclaration named parameter, you can the following on for size:

    Type[] genericTypeArguments = null;

	int typeGenericCount = parameter.DeclaringMethod.DeclaringType.GenericParameters.Count;

	if (0 < typeGenericCount)
	{
		genericTypeArguments = new Type[typeGenericCount];

		for (int i = 0; i < typeGenericCount; i++)
		{
		  genericTypeArguments[i]
                    = parameter.DeclaringMethod
                        .DeclaringType.GenericParameters[i].GetSystemType(null, null);
		}
	}

	return genericTypeArguments;

Time to Weave

The IAdvice interface provides a method named Weave, which will be invoked by PostSharp at build-time when it is our turn to get down and dirty. Note that this is not invoked by our processor task class; rather, our task class makes the invocation possible by registering the advice with PostSharp.

We now need to change our thinking; we have to think in MSIL now. What is our strategy?

Let’s just ahead to when we want to invoke our validation routine. We most likely want to do so at the start of method execution, within the body.

So, while we’re in the method body, we’ll want to probably get the declaration that is on our parameter and invoke the validation method exposed by it. Then we’re done right?

Well, maybe, but doing what I just described is bad because:

  1. It requires us to use some heavy reflection (in order to retrieve the applied attribute from the parameter). Not acceptable given the frequency that this code will be going off.
  2. Doing the proposed steps above sounds less than trivial to me using MSIL. We don’t have anything fancy at our disposal here.

Let’s change our strategy. Our advice should instead:

  1. Inject some instructions into the declaring type’s static constructor that will set a unique field to reference an instance of our validation aspect.
  2. Inject some instructions before the method’s body that will invoke the validation method using the already initialized static field.

That sounds a little better. Serializing the aspect will result in an initialization that is faster (I’d hope) than the alternative. Just be aware that the size of your assembly will grow as much as you should think it would.

A few concerns remain:

  1. How do we prepare the validation attribute so that its corresponding field can be quickly set to it at run-time?
  2. What should we name the field referencing the aspect? How do we deal with multiple attributes applied on different parameters?
  3. How do we actually invoke the validation method?

For #1, this is simple. We’ll go about doing this by serializing the attribute itself into a string, and then making use of the static DeserializeStringmethod, exposed by the attribute itself type itself, in order to deserialize it.

For #2, we’ll be sure to use a GUID when naming the field.

For #3, we’ll make use of the MethodBase exposed by all validation attributes and weave in the correct instructions that will make a call to the method.

Shown below is how you can do all of this stuff using the Weaver. Most of the time when we’re weaving, we should have been provided an instance of the type WeavingContext named context, and an instance of the type InstructionBlock named block.

Getting Instance of Validator

    TValidationAttribute validator = (TValidationAttribute)_attribute.ConstructRuntimeObject();

Refer to the above whenever you see a variable named “validator” in the remaining code snippets.

Weave Attribute Field Initialization (Static Constructor)

    // This is a lovely time to invoke the compile-time validation routine on our attribute,
    // by the way.

    InstructionWriter writer = context.InstructionWriter;
    InstructionSequence entrySequence = context.Method.MethodBody.CreateInstructionSequence();

    block.AddInstructionSequence(entrySequence, NodePosition.Before, null);
    writer.AttachInstructionSequence(entrySequence);
    writer.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden);

    writer.EmitInstructionString(OpCodeNumber.Ldstr,
                                 new LiteralString(SerializeToString(validator)));

    IMethod deserializeFromString
        = context.Method.Module.FindMethod(
            ReadMethodBase(x => ValidationAttribute.DeserializeFromString(x)),
            BindingOptions.Default);

    writer.EmitInstructionMethod(OpCodeNumber.Call, deserializeFromString);
    writer.EmitInstructionField(OpCodeNumber.Stsfld, GetAttributeField(context));
    writer.DetachInstructionSequence();

For the serialize to string method: there is nothing special going on here that warrants providing it; serialization is as serialization does.

Static Field Declaration and Retrieval

    /// <summary>
    /// Gets the attribute field containing the deserialized validation attribute. If no such field
    /// exists, this will add the field to the class before returning the declaration.
    /// </summary>
    /// <param name="context">The current weaving context, provided by PostSharp.</param>
    /// <remarks>
    /// It is important that the validation attribute field be declared in this method, as
    /// references to the field are made in multiple parts of the code that gets injected.
    /// This method should always be used whenever a reference to the field is needed in an
    /// injection.
    /// </remarks>
    /// <returns>
    /// The <see cref="FieldDefDeclaration"/> object for the attribute field containing the
    /// deserialized validation attribute.
    /// </returns>
    protected IField GetAttributeField(WeavingContext context)
    {
        if (null != _field)
            return _field;

        string name
            = ((MemberRefDeclaration) _attribute.Constructor).DeclaringType.GetReflectionName();

        name = String.Format(CultureInfo.InvariantCulture,
                                Strings.BaseNameFormat,
                                name.Replace('.', '_'),
                                Guid.NewGuid());

        FieldDefDeclaration field = new FieldDefDeclaration
                        {
                            Name = name,
                            Attributes = FieldAttributes.Static | FieldAttributes.Private,
                            FieldType = _attribute.Constructor.DeclaringType,
                        };

        context.Method.DeclaringType.Fields.Add(field);

        GenericFieldReference fieldReference = context.Method.DeclaringType.FindField(name);

        _field = fieldReference.Field.GetCanonicalGenericInstance();

        return _field;
    }

This one actually took me a bit to get right. At first, the fields I was spitting out were causing some pretty low level errors having to do with generics that served to teach me a few things I didn’t know. The above should support non-generic and generic classes.

Weave Validation Invocation into Method

    InstructionWriter writer = context.InstructionWriter;
    InstructionSequence entrySequence = context.Method.MethodBody.CreateInstructionSequence();

    block.AddInstructionSequence(entrySequence, NodePosition.Before, null);
    writer.AttachInstructionSequence(entrySequence);
    writer.EmitSymbolSequencePoint(SymbolSequencePoint.Hidden);

	InstructionWriter writer = context.InstructionWriter;

	writer.EmitInstructionField(OpCodeNumber.Ldsfld, GetAttributeField(context));
	writer.EmitInstruction(context.Method.GetFirstParameterCode());
	writer.EmitInstructionInt16(
            OpCodeNumber.Ldarg,
            (short) (_parameterIndex + context.Method.GetFirstNonImplicitParameterIndex()));

	if (BoxingIsRequired)
		writer.EmitInstructionType(OpCodeNumber.Box, _parameter.ParameterType);

	writer.EmitInstructionString(OpCodeNumber.Ldstr, _parameter.Name);

	IMethod validation
            = context.Method.Module.FindMethod(validator.ValidationMethod, BindingOptions.Default);

	writer.EmitInstructionMethod(validator.ValidationMethod.GetFirstParameterCode(), validation);

    writer.DetachInstructionSequence();

I noticed I left a few extension methods in here.

For GetFirstParameterCode(): Use OpCodeNumber.Ldnull if the method is static, otherwise use OpCodeNumber.Ldarg_0.

For GetFirstNonImplicitParameterIndex: Return 0 if static, 1 otherwise.

Check If Boxing is Needed

I think this is correct. Doublecheck!

   Type parameterType
       = _parameter.ParameterType.GetSystemType(_genericTypeArguments, _genericMethodArguments);

   if (parameterType.ContainsGenericParameters)
       return true;

   int validatorTargetIndex = validator.ValidationMethod.GetFirstNonImplicitParameterIndex();

   return parameterType.IsValueType
    && !validator.ValidationMethod.GetParameters()[validatorTargetIndex].ParameterType.IsValueType;

There you go. In the end, you should have aspects you can apply like so:

    public bool Process([NotNull]CreditCard card, int csv)
    {
        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number, csv);
    }

Or even…

    public bool Process(
        [NotNull(Exception=typeof(CompletelyUnrelatedExceptionTypeForFunAndProfit)]CreditCard card,
        int csv)
    {
        if (card.Brand == CreditCardBrands.MasterCard)
        {
            // MasterCard? Denied!!!
            return false;
        }

        return Process(card.Number, csv);
    }

Which results in a very light weight injection of instructions in order to validate the parameter which the attribute is applied to.

© 2012-2013 Matt Weber. All Rights Reserved. Terms of Use.