I had a request for an ASP.NET version of my windows forms About Box. This is a good idea that I've considered in the past, so I took the time to convert it today:
Clicking details will provide a dump of all loaded assemblies in summary form, with links to the full list of the attributes for each assembly-- exactly the same information the windows forms version provides.
The main page is a HTML template; you can make it look however you want by modifying the markup-- no recompilation required. To display entry assembly attributes, use the named properties defined in the About class, eg Version <%=Version%>, or call EntryAssemblyAttrib(key) with any arbitrary attribute key you want to display.
Oh, and populate your damn assembly attributes, because that's where all this information is automatically derived from:
<Assembly: AssemblyTitle("About Page Demo")>
<Assembly: AssemblyDescription("A website demonstrating the About page")>
<Assembly: AssemblyCompany("Atwood Heavy Industries")>
<Assembly: AssemblyProduct("Demos")>
<Assembly: AssemblyCopyright(" 2005, Atwood Heavy Industries")>
<Assembly: AssemblyTrademark("All Rights Reserved")>
I don't think this is enough to justify another CodeProject article, so I'll host it here and link it from the comments in the original article.
Download the ASP.NET About Page VS.NET 2003 project (12kb)
c# version of about.aspx.vb if anyone finds this:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.Win32;
namespace Example.AdminSite
{
public class Default : System.Web.UI.Page
{
private String _CallingAssemblyName;
private String _ExecutingAssemblyName;
private System.Reflection.Assembly _EntryAssembly;
private NameValueCollection _EntryAssemblyAttribCollection;
protected void Page_Load(object sender, EventArgs e)
{
_EntryAssembly = Assembly.GetExecutingAssembly();
_ExecutingAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
_CallingAssemblyName = Assembly.GetCallingAssembly().GetName().Name;
// for an ASP.NET app, entry assembly is something of a misnomer;
// what we really have is ExecutingAssembly
_EntryAssemblyAttribCollection = AssemblyAttribs(_EntryAssembly);
}
private void Page_PreRender(Object sender, System.EventArgs e)
{
}
public string AssemblyTitle { get { return EntryAssemblyAttrib("Title"); } }
public string Copyright { get { return EntryAssemblyAttrib("copyright"); } }
public string Description { get { return EntryAssemblyAttrib("description"); } }
public string Company { get { return EntryAssemblyAttrib("company"); } }
public string Product { get { return EntryAssemblyAttrib("product"); } }
public string Trademark { get { return EntryAssemblyAttrib("trademark"); } }
public string Version { get { return EntryAssemblyAttrib("version"); } }
public string BuildDate { get { return EntryAssemblyAttrib("builddate"); } }
public string RuntimeVersion { get { return Regex.Match(Environment.Version.ToString(), @"\d+.\d+.\d+").ToString(); } }
public String EntryAttrib(String key) { return EntryAssemblyAttrib(key); }
public void RenderDetails()
{
RenderAppDetails();
RenderAssemblyDetails();
}
/// summary
/// exception-safe retrieval of LastWriteTime for this assembly.
/// /summary
/// returnsFile.get {LastWriteTime, or DateTime.MaxValue if exception wencountered./returns
protected internal DateTime AssemblyLastWriteTime(System.Reflection.Assembly a)
{
try
{
return File.GetLastWriteTime(a.Location);
}
catch (Exception exception)
{
return DateTime.MaxValue;
}
}
/// summary
/// returns DateTime this Assembly wlast built. Will attempt to calculate from build number, if possible.
/// If not, the actual LastWriteTime on the assembly file will be returned.
/// /summary
/// param name="a"Assembly to get { build date for/param
/// param name="ForceFileDate"Don't attempt to use the build number to calculate the date/param
/// returnsDateTime this assembly wlast built/returns
protected DateTime AssemblyBuildDate(System.Reflection.Assembly a, bool ForceFileDate)
{
System.Version AssemblyVersion = a.GetName().Version;
DateTime dt;
if (ForceFileDate)
dt = AssemblyLastWriteTime(a);
else
{
dt = new DateTime(2000, 1, 1).AddDays(AssemblyVersion.Build).AddSeconds(AssemblyVersion.Revision * 2);
if (TimeZone.IsDaylightSavingTime(dt, TimeZone.CurrentTimeZone.GetDaylightChanges(dt.Year)))
dt = dt.AddHours(1);
if (dt DateTime.Now || AssemblyVersion.Build 730 || AssemblyVersion.Revision == 0)
dt = AssemblyLastWriteTime(a);
}
return dt;
}
protected DateTime AssemblyBuildDate(System.Reflection.Assembly a)
{
return AssemblyBuildDate(a, false);
}
/// summary
/// returns string name / string value pair of all attribs
/// for specified assembly
/// /summary
/// remarks
/// note that Assembly* values are pulled from AssemblyInfo file in project folder
///
/// Trademark = AssemblyTrademark string
/// Debuggable = True
/// GUID = 7FDF68D5-8C6F-44C9-B391-117B5AFB5467
/// CLSCompliant = True
/// Product = AssemblyProduct string
/// Copyright = AssemblyCopyright string
/// Company = AssemblyCompany string
/// Description = AssemblyDescription string
/// Title = AssemblyTitle string
/// /remarks
private NameValueCollection AssemblyAttribs(System.Reflection.Assembly a)
{
String TypeName;
String Name;
String Value;
NameValueCollection nvc = new NameValueCollection();
Regex r = new Regex("(\\.Assembly|\\.)(?Name[^.]*)Attribute$", RegexOptions.IgnoreCase);
foreach (Object attrib in a.GetCustomAttributes(false))
{
TypeName = attrib.GetType().ToString();
Name = r.Match(TypeName).Groups["Name"].ToString();
Value = "";
switch (TypeName)
{
case "System.CLSCompliantAttribute":
Value = ((CLSCompliantAttribute)attrib).IsCompliant.ToString();
break;
case "System.Diagnostics.DebuggableAttribute":
Value = ((DebuggableAttribute)attrib).IsJITTrackingEnabled.ToString();
break;
case "System.Reflection.AssemblyCompanyAttribute":
Value = ((AssemblyCompanyAttribute)attrib).Company.ToString();
break;
case "System.Reflection.AssemblyConfigurationAttribute":
Value = ((AssemblyConfigurationAttribute)attrib).Configuration.ToString();
break;
case "System.Reflection.AssemblyCopyrightAttribute":
Value = ((AssemblyCopyrightAttribute)attrib).Copyright.ToString();
break;
case "System.Reflection.AssemblyDefaultAliasAttribute":
Value = ((AssemblyDefaultAliasAttribute)attrib).DefaultAlias.ToString();
break;
case "System.Reflection.AssemblyDelaySignAttribute":
Value = ((AssemblyDelaySignAttribute)attrib).DelaySign.ToString();
break;
case "System.Reflection.AssemblyDescriptionAttribute":
Value = ((AssemblyDescriptionAttribute)attrib).Description.ToString();
break;
case "System.Reflection.AssemblyInformationalVersionAttribute":
Value = ((AssemblyInformationalVersionAttribute)attrib).InformationalVersion.ToString();
break;
case "System.Reflection.AssemblyKeyFileAttribute":
Value = ((AssemblyKeyFileAttribute)attrib).KeyFile.ToString();
break;
case "System.Reflection.AssemblyProductAttribute":
Value = ((AssemblyProductAttribute)attrib).Product.ToString();
break;
case "System.Reflection.AssemblyTrademarkAttribute":
Value = ((AssemblyTrademarkAttribute)attrib).Trademark.ToString();
break;
case "System.Reflection.AssemblyTitleAttribute":
Value = ((AssemblyTitleAttribute)attrib).Title.ToString();
break;
case "System.Resources.NeutralResourcesLanguageAttribute":
Value = ((System.Resources.NeutralResourcesLanguageAttribute)attrib).CultureName.ToString();
break;
case "System.Resources.SatelliteContractVersionAttribute":
Value = ((System.Resources.SatelliteContractVersionAttribute)attrib).Version.ToString();
break;
case "System.Runtime.InteropServices.ComCompatibleVersionAttribute":
System.Runtime.InteropServices.ComCompatibleVersionAttribute x;
x = attrib as System.Runtime.InteropServices.ComCompatibleVersionAttribute;
Value = string.Format("{0}.{1}.{2}.{3}", x.MajorVersion, x.MinorVersion, x.RevisionNumber, x.BuildNumber);
break;
case "System.Runtime.InteropServices.ComVisibleAttribute":
Value = ((System.Runtime.InteropServices.ComVisibleAttribute)attrib).Value.ToString();
break;
case "System.Runtime.InteropServices.GuidAttribute":
Value = ((System.Runtime.InteropServices.GuidAttribute)attrib).Value.ToString();
break;
case "System.Runtime.InteropServices.TypeLibVersionAttribute":
System.Runtime.InteropServices.TypeLibVersionAttribute tlva = attrib as System.Runtime.InteropServices.TypeLibVersionAttribute;
Value = tlva.MajorVersion + "." + tlva.MinorVersion;
break;
case "System.Security.AllowPartiallyTrustedCallersAttribute":
Value = "(Present)";
break;
default:
// debug.writeline("** unknown assembly attribute '" TypeName "'")
Value = TypeName; break;
}
if (string.IsNullOrEmpty(nvc[Name]))
nvc.Add(Name, Value);
}
// add some extra values that are not in the AssemblyInfo, but nice to have
// codebase
try { nvc.Add("CodeBase", a.CodeBase.Replace("file:///", "")); }
catch (System.NotSupportedException ex) { nvc.Add("CodeBase", "(not supported)"); }
// build date
DateTime dt = AssemblyBuildDate(a);
if (dt == DateTime.MaxValue)
nvc.Add("BuildDate", "(unknown)");
else
nvc.Add("BuildDate", dt.ToString("yyyy-MM-dd hh:mm tt"));
// location
try { nvc.Add("Location", a.Location); }
catch (System.NotSupportedException ex) { nvc.Add("Location", "(not supported)"); }
// version
try
{
if (a.GetName().Version.Major == 0 a.GetName().Version.Minor == 0)
nvc.Add("Version", "(unknown)");
else
nvc.Add("Version", a.GetName().Version.ToString());
}
catch (Exception ex) { nvc.Add("Version", "(unknown)"); }
nvc.Add("FullName", a.FullName);
return nvc;
}
/// summary
/// Render a row with the specified key and value strings
/// /summary
public void RenderRow(String Key, String Value)
{
if (string.IsNullOrEmpty(Value)) return;
Response.Write("TR");
Response.Write("TD");
Response.Write("SPAN class='key'");
Response.Write(Key);
Response.Write("/SPANTD");
Response.Write("SPAN class='value'");
Response.Write(Value);
Response.Write("/SPAN/TR");
Response.Write(Environment.NewLine);
}
/// summary
/// populates the Application Information listview
/// /summary
private void RenderAppDetails()
{
Response.Write("DIV class='header'Application Details/DIV");
Response.Write("TABLE width=\"100%\"");
Response.Write("TRTH width=\"200px\"KeyTH width=\"*\"Value/TR");
System.AppDomain d = System.AppDomain.CurrentDomain;
RenderRow("Application Name", d.SetupInformation.ApplicationName);
RenderRow("Application Base", d.SetupInformation.ApplicationBase);
RenderRow("Cache Path", d.SetupInformation.CachePath);
RenderRow("Configuration File", d.SetupInformation.ConfigurationFile);
RenderRow("Dynamic Base", d.SetupInformation.DynamicBase);
RenderRow("Friendly Name", d.FriendlyName);
RenderRow("License File", d.SetupInformation.LicenseFile);
RenderRow("private Bin Path", d.SetupInformation.PrivateBinPath);
RenderRow("Shadow Copy Directories", d.SetupInformation.ShadowCopyDirectories);
RenderRow("Executing Assembly", _ExecutingAssemblyName);
RenderRow("Calling Assembly", _CallingAssemblyName);
Response.Write("/TABLE");
Response.Write("P/P");
}
/// summary
/// RenderRow Assembly Information listview with ALL assemblies
/// /summary
private void RenderAssemblyDetails()
{
Response.Write("DIV class='header'");
Response.Write("Loaded Assemblies");
Response.Write("/DIV");
Response.Write("TABLE width=\"100%\"");
Response.Write("TRTH width=\"200px\"AssemblyTH width=\"150px\"Version");
Response.Write("TH width=\"200px\"BuiltTH width=\"*\"Filename/TR");
// sort the assemblies first
SortedList sl = new SortedList();
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
sl.Add(a.GetName().Name, null);
}
foreach (DictionaryEntry de in sl)
RenderAssemblySummary(MatchAssemblyByName(Convert.ToString(de.Key)));
Response.Write("/table");
Response.Write("p/p");
foreach (DictionaryEntry de in sl)
{
Assembly a = MatchAssemblyByName(Convert.ToString(de.Key));
Response.Write("DIV class='header'");
Response.Write("A name=\"" + a.GetName().Name + "\"" + a.GetName().Name + "/a");
Response.Write("/DIV");
Response.Write("BLOCKQUOTE");
Response.Write("TABLE width=\"100%\"");
Response.Write("TRTH width=\"200px\"KeyTH width=\"*\"Value/TR");
RenderAssemblyDetails(a);
Response.Write("/TABLE");
Response.Write("/BLOCKQUOTE");
}
}
/// summary
/// Render Assembly Information listview with summary view for a specific assembly
/// /summary
private void RenderAssemblySummary(Assembly a)
{
NameValueCollection nvc = AssemblyAttribs(a);
String strAssemblyName = a.GetName().Name;
Response.Write("TR");
Response.Write("TD");
Response.Write("A href=\"#" + strAssemblyName + "\"");
Response.Write(strAssemblyName);
Response.Write("/A");
if (strAssemblyName == _CallingAssemblyName)
Response.Write(" (calling)");
if (strAssemblyName == _ExecutingAssemblyName)
Response.Write(" (executing)");
Response.Write("TDSPAN class='version'");
Response.Write(nvc["version"]);
Response.Write("/SPANTDSPAN class='builddate'");
Response.Write(nvc["builddate"]);
Response.Write("/SPANTDSPAN class='filename'");
Response.Write(Path.GetFileName(nvc["codebase"]));
Response.Write("/SPAN/TR");
}
/// summary
/// retrieves a cached value from the entry assembly attribute lookup collection
/// /summary
private String EntryAssemblyAttrib(String strName)
{
if (string.IsNullOrEmpty(_EntryAssemblyAttribCollection[strName]))
return "[Assembly: Assembly" + strName + "(\"\")]";
else
return _EntryAssemblyAttribCollection[strName].ToString();
}
/// summary
/// Render details for a single assembly
/// /summary
private void RenderAssemblyDetails(System.Reflection.Assembly a)
{
// this assembly string is only available in framework versions 1.1+
RenderRow("Image Runtime Version", a.ImageRuntimeVersion);
RenderRow("Loaded from GAC", a.GlobalAssemblyCache.ToString());
NameValueCollection nvc = AssemblyAttribs(a);
foreach (String strKey in nvc)
RenderRow(strKey, nvc[strKey]);
}
/// summary
/// matches assembly by Assembly.get {Name.Name; returns nothing if no match
/// /summary
private Assembly MatchAssemblyByName(String AssemblyName)
{
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
if (a.GetName().Name == AssemblyName)
return a;
}
return null;
}
#region Event wireup
protected override void OnInit(EventArgs e)
{
this.Load += new EventHandler(Page_Load);
this.PreRender += new EventHandler(Page_PreRender);
base.OnInit(e);
}
#endregion
}
}
Thanks Jeff.
Here is the aspx for C#, which required minimalistic changes:
%@ Page Language=C# AutoEventWireup=true CodeFile=About.aspx.cs Inherits=About %
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlns=http://www.w3.org/1999/xhtml
head id=Head1 runat=server
titleAbout %=Title%/title
meta name=vs_targetSchema content=http://schemas.microsoft.com/intellisense/ie5 /
style type=text/css
body
{ font-family: tahoma; font-size:80%; }
TH
{ text-align: left; font-family: verdana; font-size:80%; }
TD
{ font-size: 80% }
.header
{ background-color: #EEEEEE; padding: 5px; margin:3px; font-size: 120%; font-weight: bold;}
.key
{ color: darkred; font-family: courier;}
.value
{ color: darkblue; font-family: courier; }
.filename
{ font-family: courier; }
.version
{ color: purple;}
.builddate
{ font-style: italic; }
.aboutdiv
{ background-color: #EEEEEE; padding: 10px; }
.aboutdivtitle
{ background-color: white; border: solid 3px #CCCCCC; padding: 5px; margin:10px;}
.title
{ font-size: 140%; font-weight: bold; }
.description
{ font-style: italic; margin-left: 20px; margin: 10px; }
/style
/head
body
form id=form1 runat=server
div class=aboutdiv
table width=95% cellpadding=0 cellspacing=0
tr
td width=500px
div class=aboutdivtitle
span class=title%=Title%/span
/div
div class=description%=Description%/div
/td
td width=*
table
tr
tdVersion %=Version%/td
/tr
tr
tdBuilt on %=BuildDate%/td
/tr
tr
tdRunning on .NET framework version %=RuntimeVersion%/td
/tr
tr
tdCopyright %=DateTime.Now.Year.ToString()%, %=Company%/td
/tr
/table
/td
/tr
/table
%=Product% is %=Copyright%, %=Trademark%
/div
table
!--
Miscellaneous application-related info that's helpful to display on an About page
(but cannot be automatically derived from assembly attributes)
--
%
String ExampleConnectionString = Data Source=Your_Server_Name;Initial Catalog=Your_Database_Name;User Id=Your_Username;Password=Your_Password;;
RenderRow(Current URL, Regex.Replace(Request.Url.ToString(), [^/]*?$, ));
RenderRow(DB Connection, Regex.Replace(ExampleConnectionString, (password=)([^;]+), $1******, RegexOptions.IgnoreCase));
%
/table
input type=button value=Details gt;gt; onclick=this.style.display='none'; document.getElementById('Details').style.display='block' /
div style='display:none;' id='Details'
%RenderDetails();%
/div
/form
/body
/html
The comments to this entry are closed.
|
|
Traffic Stats |