+4  A: 

No, it is not possible to hook into the compilation of the assembly and check if it exists.

However you can hook into the build process, which is made up of more than just running the compiler. You could create a custom MSBUILD task (or NAnt, if you are using that) which checks the assembly through reflection after it is built and then fail the build if it doesn't have the required attributes.

Of course, you should probably still verify this in code as well. What you are trying to do is not a good substitute for a proper runtime check.

casperOne
Thaks for answering!What do you mean more specifically by "What you are trying to do is not a good substitute for a proper runtime check."?
YordanGeorgiev
@YordanGeorgiev: Even if you have a build process which makes sure the attribute is applied, you should STILL check in your runtime code to make sure that the attribute is applied. You can't stop checking there because you think you caught it at compile time.
casperOne
So the requirement for getting at least 4 "must have" attributes will affect performance , because of reflection ...Seems that performing the checks in Unit tests will be than better idea ?!
YordanGeorgiev
What bothered me also was that MSBUILD is not meant for Web projects ... and NAnt seems just too heavy to such a "simple" requirement ( or may be "simple" is due to my inexperience ...)
YordanGeorgiev
@casperOne: I still don't get why do you think runtime checks are needed, at least if your assemblies have strong names.
Anton Tykhyy
+1  A: 

Attributes are run time only. However :

It would be possible to create a rule in FXCop (static analysis) that will fail if the attribute is not defined, and your build/checkin process could check that rule and fail appropriately.

Jason Coyne
Not 100% true. "Obsolete" and "Conditional" are both compile time attributes.
Michael Meadows
+1  A: 

I'm not aware of any way to hook into the C# compilation process, but you may take a different approach and create a custom tool launched on the post build event which could load your assembly and reflects on that. Depending on what the tool returns the whole build process will result in a success or a failure, so you may just return an error with your tool and make the build fail, while providing more details about the failure writing to console.

emaster70
I added a small draft of this type of a tool bellow
YordanGeorgiev
+3  A: 

You can run a post-build step that reflects on the DLL to do what you want.

You will have to write a command-line app that loads the DLL and reflects on the types. You then run that command-line app as a post-build step. I have done this in the past. It is not terribly difficult to do, assuming you understand the reflection API.

PostSharp does this to achieve aspect oriented programming. Pretty cool, actually.

Brian Genisio
Brian , thanks!Looked promising I 'll check it tomorrow ... Here in Finland is 10:43 pm now. If I figure out something meaningful I will post the code ...
YordanGeorgiev
Arggh ... smells that it will be converted to close solution ...
YordanGeorgiev
+1  A: 

To me this seems more like a testing problem than a compilation problem. That is, you're asking "how do I know that my code is written correctly?" where "written correctly" has (among other things) the connotation that all classes are decorated with a particular attribute. I would consider writing unit tests that verify that your attribute inclusion rules are, in fact, followed. You could have your build (and/or checkin) process run this particular set of tests after the build (before the checkin) as a condition of a successful build (checkin). It won't break the compile, since that needs to complete in order for the tests to run, but it will break the build, so to speak.

tvanfosson
My fear is that Unit tests are not always 100% suitable for the whole build.I have seen also cheating on unit tests to some degree ...In the context of the question if the whole think would not even compile and the forcing custom attributes are minimal ( for example Author , Version )
YordanGeorgiev
I would write probably a single unit test per attribute. It would go through all of the classes in the assembly (or methods in classes) and verify the existence of the attribute. You wouldn't have to write a separate test for each class/method.
tvanfosson
Thanks for answer tvanfosson !You where correct to point out that this check should be performed as a part of the unit testing processI added a code snippet of an example how it could be done (however not as a part of particular unit test since one could use NUnit , PEX or whatever else and I do not know all the variations ...Your answer reminded me that one should always look first at the big picture and later on start coding ...
YordanGeorgiev
+1  A: 
//PLEASE COMMENT IF YOU FIND BUGS OR SUGGEST IMPROVEMENTS


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace MustHaveAttributes
{
 [AttributeClass ( "Yordan Georgiev", "1.0.0" )] 
 class Program
 {


 static void Main ( string [] args )
 {
  bool flagFoundCustomAttrOfTypeAttributeClass = false; 
  Console.WriteLine ( " START " );

  // what is in the assembly
  Assembly a = Assembly.Load ( "MustHaveAttributes" );
  Type[] types = a.GetTypes ();
  foreach (Type t in types)
  {
   object[] arrCustomAttributes = t.GetCustomAttributes ( true );


   if (arrCustomAttributes == null || arrCustomAttributes.GetLength ( 0 ) == 0)
   {
    //DO NOT CHECK IN
    ExitProgram ( t, "Found class without CustomAttributes" );
   }


   foreach (object objCustomAttribute in arrCustomAttributes)
   {
    Console.WriteLine ( "CustomAttribute for type  is {0}", t );
    if (objCustomAttribute is AttributeClass)
     flagFoundCustomAttrOfTypeAttributeClass = true; 
   }

   if (flagFoundCustomAttrOfTypeAttributeClass == false)
   { //DO NOT CHECK IN 
    ExitProgram ( t, "Did not found custom attribute of type AttributeClass" );
   }
   Console.WriteLine ( "Type is {0}", t );
  }
  Console.WriteLine ("{0} types found", types.Length );

  //NOW REQUIREMENTS IS PASSED CHECK IN
  Console.WriteLine ( " HIT A KEY TO EXIT " );
  Console.ReadLine ();
  Console.WriteLine ( " END " );
 }



 static void ExitProgram ( Type t, string strExitMsg  )
 {

  Console.WriteLine ( strExitMsg );
  Console.WriteLine ( "Type is {0}", t );
  Console.WriteLine ( " HIT A KEY TO EXIT " );
  Console.ReadLine ();

  System.Environment.Exit ( 1 );

 }
} //eof Program


//This will fail even to compile since the constructor requires two params
//[AttributeClass("OnlyAuthor")]  
//class ClassOne
//{ 

//} //eof class 


////this will not check in since this class does not have required custom
////attribute
//class ClassWithoutAttrbute
//{ }



[AttributeClass("another author name " , "another version")]
class ClassTwo
{ 

} //eof class


[System.AttributeUsage ( System.AttributeTargets.Class |
 System.AttributeTargets.Struct, AllowMultiple = true )]
public class AttributeClass : System.Attribute
{

 public string MustHaveDescription { get; set; }
 public string MusHaveVersion { get; set; }


 public AttributeClass ( string mustHaveDescription, string mustHaveVersion )
 {
  MustHaveDescription = mustHaveDescription;
  MusHaveVersion = mustHaveVersion;
 }

} //eof class

} //eof namespace

YordanGeorgiev