Actually, it is possible during the build process to use a custom attribute
to embed a build timestamp, or other metadata for that matter. The only
requirement is that it has to be a custom permission attribute, which do get
instantiated during compilation time. Granted, this is a very obscure
solution, and probably not very practical, but what did you expect for a
Friday afternoon?

Of course it isn't very pretty. You have to include a SecurityAction.Demand
parameter which looks out of place. It is also necessary to build the custom
permission as a separate assembly.

// ----------------- BuildAttributeTest.cs --------------------------------
// This is a test program showing how it can be used.

[ BuildAttribute( System.Security.Permissions.SecurityAction.Demand ) ]
class Class1
{
    static void Main ( )
    {
        Console.WriteLine( "Program compiled by {0} on {1}",
                    BuildAttribute.Developer, BuildAttribute.Date );
    }
}

If you compile this program the output will be

 'Program compiled by fernando on 1/28/2005 5:44:01 PM'

but with a different build time and user name, of course.

// ----------------- BuildAttribute.cs --------------------------------
// This is the code for the custom permission attribute class.

[ AttributeUsage( AttributeTargets.Class, AllowMultiple = false ) ]
public sealed class BuildAttribute : CodeAccessSecurityAttribute
{
    private const string ATTRIBUTE_DATE = "date";
    private const string ATTRIBUTE_DEVELOPER = "developer";

    public BuildAttribute ( SecurityAction action ) : base( action )
    {
    }

    public override IPermission CreatePermission ( )
    {
        SecurityElement se = new SecurityElement( "BuildMetaData" );
        se.AddAttribute( ATTRIBUTE_DATE,
                                   DateTime.Now.ToFileTime( ).ToString( ) );
        se.AddAttribute( ATTRIBUTE_DEVELOPER,
                                       Environment.UserName );
        return new BuildMetaData( se );
    }

    public static DateTime Date
    {
        get
        {
              long buildTime = long.Parse( ( string )
                   BuildMetaData.Value.Attributes[ ATTRIBUTE_DATE ] );
              return DateTime.FromFileTime( buildTime );
         }
    }

    public static string Developer
    {
        get { return ( string )
                BuildMetaData.Value.Attributes[ ATTRIBUTE_DEVELOPER ]; }
    }
}


// ----------------- BuildMetaData.cs --------------------------------
// This is the code for the custom permission class.

public class BuildMetaData : IPermission, ISecurityEncodable
{
    private const string XML_TAGNAME = "Permission";
    private const string XML_ATTRIBUTE_CLASS = "class";

    private static SecurityElement _value;

    internal static SecurityElement Value
    {
        get { return _value; }
    }

    internal BuildMetaData ( SecurityElement value )
    {
        _value = value;
    }

    public BuildMetaData ( PermissionState state ) { }

    public IPermission Copy ( )
    {
        return new BuildMetaData( _value );
    }

    public void Demand ( ) { }

    public IPermission Intersect ( IPermission target )
    {
        if( null == target )
            return null;

        CheckType( target );

        return new BuildMetaData( _value );
    }

    public bool IsSubsetOf ( IPermission target )
    {
        if( null == target )
            return false;

        CheckType( target );

        return true;
    }

    public IPermission Union ( IPermission target )
    {
        if ( null == target )
            return Copy( );

        CheckType( target );

        return new BuildMetaData( _value );
    }

    public void FromXml ( SecurityElement e )
    {
        if ( null == e )
            throw new ArgumentNullException( "e" );

        if ( e.Tag != XML_TAGNAME )
            throw new ArgumentException( "Invalid BuildMetaData element." );

        _value = e.Children[ 0 ] as SecurityElement;
    }

    public SecurityElement ToXml (  )
    {
        Type type = typeof( BuildMetaData );
        SecurityElement securityElement =
                  new SecurityElement( XML_TAGNAME );
        securityElement.AddAttribute(
                  XML_ATTRIBUTE_CLASS, type.FullName + ", " +
                  type.Module.Assembly.FullName.Replace( "\"", "'" ) );
        securityElement.AddChild( _value );
        return securityElement;
    }

    private void CheckType ( IPermission target )
    {
        if ( target.GetType( ) != typeof( BuildMetaData ) )
            throw new ArgumentException(
                String.Format( "Type is not compatible with {0}.",
                        typeof( BuildMetaData ).FullName ), "target" );
    }
}

If you are using Visual Studio, you have to first build the custom
permission and custom permission attribute into a separate assembly, which
must then be copied to the root folder of the test project before this can
be compiled.

Fernando Tubio

----- Original Message -----
From: "Ian Griffiths" <[EMAIL PROTECTED]>
Sent: Thursday, January 27, 2005 12:14 PM
Subject: Re: Determing time when a assembly was built


>> <snip>
>> And if you mean something like this:
>>
>> [assembly:BuildTimeStamp("2005-01-25 14:58:00")]
>>
>> then that doesn't really help.  It still leaves needing a solution to
>> exactly the same problem Raj posed in the first place: how do you
>> arrange for that text string to be whatever the time of day is at
when
>> the build occurred?
>>
>> </snip>
>
> Given that you can keep your assembly attribute info in multiple
> files this could be easily achieved with a console app rewriting this
> one attribute into a file in the prebuild event.

...well yes - I suggested using a prebuild step in the message I sent
before the one you quoted.  :-)  (I even posted an example of how to do
it!)  Still, what can you expect if you ask a rhetorical question?  ;-)

The real question I was trying to ask (and evidently failing to ask with
sufficient clarity) was: does Stoyan something I don't know about custom
attributes?  He seemed to be implying that you could solve the original
problem simply by using a custom attribute.

Since the original problem was essentially one of how you get the build
timestamp in there in the first place, I could see how custom attributes
offer any particularly helpful solution to that part - you were still
left with the problem of: "Yes, but how do I get the timestamp in
there?"

Once you've worked out how to get a timestamp string into a file as part
of your build process, a custom attribute is certainly one place you
might choose to put that.  But I'm not aware of any way of using custom
attributes that means you don't still need the prebuild step to get the
string in there.  (I.e. as far as I'm aware, it doesn't really matter
whether you put the info into a custom attribute or a string constant,
or an embedded resource, or even encoded into the name of a function
that you then read out via reflection! Either way you'll be generating a
source file in a pre-build step.)

I was just wondering if I was wrong, and there was some more cunning
solution that I'm missing.

--
Ian Griffiths

===================================
This list is hosted by DevelopMentor�  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

===================================
This list is hosted by DevelopMentor�  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to