3

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.

Ev.
  • 7,109
  • 14
  • 53
  • 87
  • 2
    Have you tried using a FilterAttribute? See http://msdn.microsoft.com/en-us/library/system.web.mvc.filterattribute.aspx – Kris Vandermotten Mar 03 '14 at 03:21
  • No I haven't. Its good suggestion, because it'll help me work out where the problem is. Unfortunately, I'd like to be able to apply the contracts across projects that are not MVC, so I think it's not the solution I'm looking for. Thank you for the input! – Ev. Mar 03 '14 at 03:29
  • 3
    Code contracts should be considered part of the method's signature, available at compile time so that the static analyzer can find them. Even if you can inject them using PostSharp, you should refrain from surprising developers by invisibly changing signatures – Panagiotis Kanavos Mar 18 '14 at 16:26
  • Are you using any DI container ? Im pretty sure this kind of stuf can be done quite easily with Castle Windsor... – Michal Levý Mar 19 '14 at 15:41
  • Keep in mind that `Contract.Requires` won't actually do anything at runtime. If you actually need to validate a condition that you can't statically ensure, you should use `Contract.Requires`. – Sam Harwell Mar 19 '14 at 16:25
  • @MichalLevý How can I do this with Castle? I'm am by no means hung up on PostSharp! Thanks! – Ev. Mar 19 '14 at 23:02
  • Take a look at [this](http://docs.castleproject.org/Windsor.Introduction-to-AOP-With-Castle.ashx) article. You can use Interceptors to add any kind of AOP behaviour to your classes. Just remember that you need to resolve your controllers from container to make it work... – Michal Levý Mar 20 '14 at 16:27
  • @MichalLevý Ah right. Okay. So does the Castle Inteceptor version of AOP happent at runtime or compile time? If it's run time, I believe we'll lose the benefit of the contract? – Ev. Mar 21 '14 at 03:56
  • Runtime OFC. If by benefit you mean static analysis, then yes. I was more focused on runtime side of thing... – Michal Levý Mar 21 '14 at 07:25
  • @MichalLevý Yup - I'm only interested in the static analysis for this particular problem, but thanks for the idea. – Ev. Mar 23 '14 at 22:50

2 Answers2

1

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);
jlvaquero
  • 8,571
  • 1
  • 29
  • 45
  • Thanks for the suggestion. Using the decorator pattern I'd have to write a decorator class for each of my classes that require contracts and override each method adding the appropriate contracts. Is that correct? – Ev. Mar 19 '14 at 23:01
  • Yes Ev. You are rigth. You double the number of each class you create. (except clases with the same interface and the same contract of course) Decorator pattern is a good way to keep responsabilities splited and expand the behavior of your clases in a clean way and works well for cross-cuttin concern but it has its drawbacks. This is why it is better to use Aspect Orient Programming like PostSharp but your case is special because contracts works in compile time too. – jlvaquero Mar 20 '14 at 06:56
  • Ah I get it. Thank you for your idea. In my case this wouldn't be so helpful because most interfaces are only used once (for DI) so I may as well write the contract in the origin method. Having said that it's a valid idea and I can see it would work in some other cases. Thanks again1 – Ev. Mar 21 '14 at 03:52
0

The AddContract class is not defined as an Attribute

[Serializable]
public class AddContractAttribute : MethodInterceptionAspect
{
Mikee
  • 1,571
  • 2
  • 14
  • 24
  • Thanks for the input @Mikee. I think the name of the class is okay (like, we don't need to append the word "Attribute" to it for it to be recognised by PostSharp. I think the face that it's inheriting from MethodInterceptionAspect should define it as an aspect (kinda an attribute) for us. – Ev. Mar 05 '14 at 23:14
  • Interesting, I'm just getting into PostSharp and I thought I read somewhere that the Aspects have to be Attributes. – Mikee Mar 06 '14 at 17:46
  • Sort of. What I mean is, it is an attribute, but the class name doesn't necessarily have to have the word "attribute" in it. – Ev. Mar 06 '14 at 23:14
  • After glancing at Code contracts and seeing how it interacts with code I bet this could be a tough situation to deal with. Have you considered replacing Code Contracts entirely with PostSharp advices? – Mikee Mar 13 '14 at 15:05
  • Code Contracts are awesome. You put them in your code to describe the behaviour of the app that wouldn't normally be apparent. Then, with the help of a plug in, the compiler will warn you about those things at compile time. It uses static analysis to work out what might happen, and find potential problems. So, if I use a contract to say: "method Y requires that parameter X be equal to 5" then I have some code calling it with x=6, I'll get a compile time issue. – Ev. Mar 14 '14 at 00:08
  • I'd like to use Postsharp (or any tool) to add a contract to "any method that has been decorated with attribute Z". But, I don't think the postsharp concept of advices is an equivalent of this. Thank you for the suggestion! – Ev. Mar 14 '14 at 00:09
  • Somebody asked your question in this recording [link] (http://www.postsharp.net/blog/post/Recording-Under-the-Hood-of-a-Post-Compiler-2b-QA) No clear answer but author did mention the PostSharp Ultimate has similar Code Contract features. – Mikee Mar 14 '14 at 15:21
  • Ah yeah, the code contracts that come with Postsharp out of the box don't quite do what I want. I want to declarative add some bespoke, very specific contracts. Thanks again. – Ev. Mar 18 '14 at 00:16
  • @Mikee Code Contracts should be considered part of the method's signature. PostSharp deals with aspects that are applied on top of that signature. Despite the implementation similarities, these are very different concepts. – Panagiotis Kanavos Mar 18 '14 at 16:23