Skip to content

How To Display the Build Date of a .NET Application

Displaying Your Build Date

Recently, I was working on EssentialCSharp.com, and I wanted to display the build date on the website. This addition allows C# developers to see the version of the site that was live and helps visitors know the site is monitored and current.

I recalled a previous IntelliTect blog post on displaying the build date on your web pages, and I knew IntelliTect had a NuGet package with the solution. However, upon installation, I realized the date returned was random between the 1900s and 2020. After searching, I realized that this previous approach has been deprecated for a few years, so I looked for a new solution. After some discussion and help from Microsoft MVP Kevin Bost, I began utilizing assembly attributes.

Creating a Build Date that Won’t Go Extinct

The journey from retrieving the build date to making it part of a NuGet package had some growing pains. Leveraging our property within MSBuild was preferable so that we didn’t have to compete with changes happening within MSBuild externally; this allowed for more longevity with our solution.

Creating the Attribute

To create this property, we began by creating the attribute. First, we created a class and methods to utilize our assembly attributes to parse the DateTime string that comes from the MSBuild step. We also wanted to ensure that the correct DateTimeKind is returned so that conversions to other time zones could easily be made without having to do something strange like adding a kind to the DateTime.

We expected the runtime to call our constructor when the attribute from our generated code was retrieved, likely in the GetReleaseDate() method. While theoretically, a user could create their own usage of the assembly attribute with code like var attribute = new ReleaseDate("date-here"), we assumed that the utcDateString parameter would come from our generated code.

The DateTimeStyles parameter in ParseExact() (or Parse()) is essential because, otherwise, .NET will try to be too helpful and automatically convert the DateTime string to the local time zone, which in our case, we do not want to do. Instead, we only want to do that conversion wherever we use the build date if a conversion is needed.

/// <summary>
/// The release date assembly attribute.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly)]
public class ReleaseDateAttribute : Attribute
{
    /// <summary> 
    /// Constructor that takes in a DateTime string
    /// </summary>
    /// <param name="utcDateString"> A DateTime 'O' (round-trip date/time) format string </param>
    public ReleaseDateAttribute(string utcDateString)
    {
        ReleaseDate = DateTime.ParseExact(utcDateString, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
    }
    /// <summary>
    /// The date the assembly was built
    /// </summary>
    public DateTime ReleaseDate { get; }
    /// <summary>
    /// Method to obtain the release date from the assembly attribute
    /// </summary>
    /// <param name="assembly">An assembly instance</param>
    /// <returns>The date time from the assembly attribute</returns>
    public static DateTime? GetReleaseDate(Assembly? assembly = null)
    {
        object[]? attribute = (assembly ?? Assembly.GetEntryAssembly())?.GetCustomAttributes(typeof(ReleaseDateAttribute), false);
        return attribute?.Length >= 1 ? ((ReleaseDateAttribute)attribute[0]).ReleaseDate : null;
    }
}
Code language: C# (cs)

Using the Attribute

Once the DateTimeStyles parameter is set, we can investigate MSBuild to see how to generate the usage of this attribute. Include within the <AssemblyAttribute Include="IntelliTect.Multitool.ReleaseDate"> says ReleaseDate; however, it maps to the ReleaseDateAttribute constructor we made above. This was done because of some magic within MSBuild that recognizes that ReleaseDateAttribute is an attribute (because of the [AttributeUsage] tag at the top), so it will still map to ReleaseDate even though one ends with the Attribute, and one does not.

Parameter1 is a DateTime object representing the current UTC date and time as a string written to a C# file as an assembly attribute after some source generation is complete (triggered by the .csproj or .targets file in our case). We used the “O” format string  (round-trip format), which includes time zone information and tells the parse step that it is reading a string in UTC DateTime. The generated code looks like this:

[assembly: IntelliTect.Multitool.ReleaseDate("2023-02-10T17:29:30.2721411Z")]Code language: C# (cs)

The .csproj or .targets file looks as follows:

<Project>
  <ItemGroup>
	<AssemblyAttribute Include="IntelliTect.Multitool.ReleaseDate">
	  <_Parameter1>$([System.DateTime]::UtcNow.ToString("O"))</_Parameter1>
	</AssemblyAttribute>
  </ItemGroup>
</Project>
Code language: C# (cs)

Using the Build Date

In the following examples, I used the IntelliTect.Multitool namespace. All these examples utilize the IntelliTect.Multitool NuGet Package, which I encourage you to add to your .NET application.

First, to utilize it in a .cshtml file, such as in an ASP.NET application, you can do the following to obtain a DateTime object:

@IntelliTect.Multitool.ReleaseDateAttribute.GetReleaseDate() // Returns a time in UTCCode language: C# (cs)

Converting the UTC DateTime Object Example

If I want to convert this UTC DateTime object into one for my local timezone that is formatted in a “d MMM, yyyy h:mm:ss tt” (ex: 8 Feb, 2023 11:36:31 AM) as utilized on EssentialCSharp.com, I can do something like the following, which will format the date and convert it to my local time zone of Pacific Standard Time.

Build: @if (IntelliTect.Multitool.ReleaseDateAttribute.GetReleaseDate() is DateTime date)
{
    @TimeZoneInfo.ConvertTimeFromUtc(date, TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time")).ToString("d MMM, yyyy h:mm:ss tt", CultureInfo.InvariantCulture)
}

Code language: C# (cs)

Obtaining the DateTime Object in C# Example

If I only want to obtain this object in C# for other uses, I can do that as well with a very similar code snippet as the first one:

DateTime? date = IntelliTect.Multitool.ReleaseDateAttribute.GetReleaseDate();Code language: C# (cs)

Wrapping Up

Try out the IntelliTect.Multitool NuGet Package to get this feature and more! To see this code in action, check out EssentialCSharp.com, a new site from IntelliTect that is our no-fluff guide to learning and becoming a better C# programmer, no matter your experience level.

More Ideas?

Do you have more ideas for features we can implement into our NuGet packages? Let me know in the comments below!

Does Your Organization Need a Custom Solution?

Let’s chat about how we can help you achieve excellence on your next project!