Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaratively Adding Code Contracts (maybe with Postsharp?)

I would like to add a Contract.Requires to every method in my code that has a parameter of a certain type. How would I achieve this?

Consider the following trivialized example:

public class ValuesController : ApiController
{
    public string Get(int id)
    {
        return GetValue(id);
    }

    private string GetValue(int id)
    {
        Contract.Requires(HttpContext.Current.Request.Headers["key"] != null);
        return id.ToString();
    }
}

How could I change that to work like:

public class ValuesController : ApiController
{
    public string Get(int id)
    {
        return GetValue(id);
    }

    [AddContract]
    private string GetValue(int id)
    {
        return id.ToString();
    }
}

Where I can then multicast the AddContract attribute.

I considered using PostSharp, but it didn't seem to work. I think this might be to do with PostSharp's IL weaving not playing nicely with the metadata created by the code contracts, but my knowledge is lacking in that area.

My attempt looked something like this:

public class ValuesController : ApiController
{
    public string Get(int id)
    {
        return GetValue(id);
    }

    [AddContract]
    private string GetValue(int id)
    {
        return id.ToString();
    }
}

[Serializable]
public class AddContract : MethodInterceptionAspect
{
    public override void OnInvoke(MethodInterceptionArgs args)
    {
        Contract.Requires(HttpContext.Current.Request.Headers["key"] != null);
        args.Proceed();
    }
}

But did not work - the static code analysis does not recognize the contract.

like image 662
Ev. Avatar asked Aug 27 '26 05:08

Ev.


1 Answers

The aproach of PostSharp is Compile-Time Weaving that means modifying the MSIL code. To make work well with System.Diagnostics.Contracts PostSharp must runs after Code Contracts.

Good news is you can use Code Contracts and PostSharp. Bad new is you can't apply Code Contracts with PostSharp.

In this case I suggest decorator pattern to aproach cross-cutting concerns:

  interface IValuesController
  {
    string Get(int id);
  }

  public class ValuesController : IValuesController
  {
    public string Get(int id)
    {
      return id.ToString();
    }
  }

  public class ValuesControllerWithContracts : IValuesController{

    private IValuesController classToDecorate;

    ValuesControllerWithContracts(IValuesController classToDecorate){
      this.classToDecorate = classToDecorate;
    }

    public string Get(int id)
    {
      //decorate get property with contracts
      Contract.Requires(HttpContext.Current.Request.Headers["key"] != null);
      return classToDecorate.Get(id);
    }

  }


  //constrution and usage, this work like a charm with Dependecy Inyection container or Factory Patterns
  IValuesController valuesController = new ValuesController();
  IValuesController valuesControllerWithContracts = new ValuesControllerWithContracts(valuesController)
  valuesControllerWithContracts.Get(1);
like image 172
jlvaquero Avatar answered Aug 29 '26 18:08

jlvaquero



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!