views:

243

answers:

2

I'm using the automatic build versioning mentioned in this question (not the selected answer but the answer that uses the [assembly: AssemblyVersion("1.0.*")] technique). I'm doing this in the footer of my Site.Master file in MVC 2. My code for doing this is as follows:

<div id="footer">
    <a href="emailto:[email protected]">[email protected]</a> - Copyright © 2005-<%= DateTime.Today.Year.ToString() %>, foo LLC. All Rights Reserved.
    - Version: <%= Assembly.GetEntryAssembly().GetName().Version.ToString() %>
</div>

The exception I get is a Object reference not set to an instance of an object because GetEntryAssembly() returns NULL. My other options don't work either. GetCallingAssembly() always returns "4.0.0.0" and GetExecutingAssembly() always returns "0.0.0.0". When I go look at my DLLs, everything is versioning as I would expect. But I cannot figure out how to access it to display in my footer!!

+7  A: 

That's because Assembly.GetEntryAssembly() is returning null: there is no "entry" assembly in an ASP.NET site (because the .NET framework is hosted in the w3wp.exe process). Assembly.GetEntryAssembly() is used to get the .exe assembly that you launched from (usually in a console or Windows application)

The reason Assembly.GetAssembly(this.GetType()) is returning an assembly with version "0.0.0.0" is because ASP.NET compiles your Site.Master file into a temporary assembly under your "ASP.NET Temporary Files" folder. this is a reference to the "generated" class.

Assembly.GetExecutingAssembly() is basically the same as Assembly.GetAssembly(this.GetType()) (except it also works when there is no "this" (e.g. in static methods).

The best way would be use explicity use a type that you know exists in the assembly you're after. As an example, I assume your "Site.Master" has a code-behind file that is compiled into the assembly. You can use that instead:

Assembly.GetAssembly(typeof(Site)).GetName().Version.ToString()

(assuming the name of the class is Site)

Dean Harding
This works! `<%= Assembly.GetAssembly(typeof(HomeController)).GetName().Version.ToString() %>`
Jaxidian
Interesting, I performed a little test by creating an HtmlHelper extension that has the Assembly.GetExecutingAssembly() call in it and I was able to call that from my Site.Master and it worked just fine! This actually is surprising to me because I modified my csproj file to have it compile my views. Am I misunderstanding what that setting does? I thought that removed all of the temporary assemblies and whatnot?
Jaxidian
Views are always compiled, the difference is you can either compile everything up-front in one go or you can compile them on-demand when the site is first accessed. Either way, they'll still be compiled into a separate DLL.
Dean Harding
Oh, I just assumed that they went into the main assembly when I compiled them up-front. Thanks for that clarification. :-)
Jaxidian
A: 

Just as another solution that people may be interested in, I've concocted these helpers to help with this problem:

public static class HtmlHelperExtensions
{
    private static string _CachedCurrentVersionDate;

    /// <summary>
    /// Return the Current Version from the AssemblyInfo.cs file.
    /// </summary>
    public static string CurrentVersion(this HtmlHelper helper)
    {
        try
        {
            var version = Assembly.GetExecutingAssembly().GetName().Version;
            return version.ToString();
        }
        catch
        {
            return "?.?.?.?";
        }
    }

    public static string CurrentVersionDate(this HtmlHelper helper)
    {
        try
        {
            if (_CachedCurrentVersionDate == null)
            {
                // Ignores concurrency issues - assuming not locking this is faster than 
                // locking it, and we don't care if it's set twice to the same value.
                var version = Assembly.GetExecutingAssembly().GetName().Version;
                var ticksForDays = TimeSpan.TicksPerDay * version.Build; // days since 1 January 2000
                var ticksForSeconds = TimeSpan.TicksPerSecond * 2 * version.Revision; // seconds since midnight, (multiply by 2 to get original)
                _CachedCurrentVersionDate = new DateTime(2000, 1, 1).Add(new TimeSpan(ticksForDays + ticksForSeconds)).ToString();
            }

            return _CachedCurrentVersionDate;
        }
        catch
        {
            return "Unknown Version Date";
        }
    }
}

This allows consumption as follows in your footer:

Version: <%= Html.CurrentVersion() %> from <%= Html.CurrentVersionDate() %>
Jaxidian