A colleague recently challenged me with this.
A number of web applications are running on a server. They all reference a common tools library. This tool library must be able to get the calling assembly without having a reference to it. This is what I came up with. Any other suggestions?
First I started with a simple test.
- Can I enumerate all the methods upstream of the currently running method? Sure, I can follow the StackTrace and enumerate those methods.
- Can I get the types running these methods? Sure, I can get the Type from a MethodBase.
- Can I get the Assembly from a Type? Yep, I can.
Here's what my test looked like:
public string GetStack()
{
StringBuilder stringBuilder = new StringBuilder();
StackTrace stackTrace = new StackTrace(0, true);
for (int i = 0; i < stackTrace.FrameCount; i++)
{
StackFrame stackFrame = stackTrace.GetFrame(i);
MethodBase methodBase = stackFrame.GetMethod();
Type type = methodBase.ReflectedType;
Assembly assembly = Assembly.GetAssembly(type);
stringBuilder.Append("<b>");
stringBuilder.Append(assembly.FullName);
stringBuilder.Append(":</b> ");
stringBuilder.Append(type.ToString());
stringBuilder.Append(".");
stringBuilder.Append(methodBase.Name);
stringBuilder.Append("<br>");
}
return stringBuilder.ToString();
}
Ok, since this one works, I can expand the idea and get that one assembly where my code came from.
///<summary>
/// Gets all the calling assemblies.
///</summary>
///<returns>An arraylist containing all the calling assemblies</returns>
///<remarks>
/// The first assembly (index=0) in the list is the currently running assembly.
/// The last assembly is the running application
///</remarks>
private ArrayList GetCallingAssemblies()
{
ArrayList assemblies = new ArrayList();
StackTrace stackTrace = new StackTrace(0, true);
for (int i = 0; i < stackTrace.FrameCount; i++)
{
StackFrame stackFrame = stackTrace.GetFrame(i);
MethodBase methodBase = stackFrame.GetMethod();
Type type = methodBase.ReflectedType;
Assembly assembly = Assembly.GetAssembly(type);
if (assemblies.Contains(assembly) == false)
assemblies.Add(assembly);
}
return assemblies;
}
///<summary>
/// Gets the starting assembly.
///</summary>
///<returns>
/// The actively running assembly.
/// For a window app, this is the .exe running.
/// For a web app, it is the web application.
///</returns>
public Assembly GetStartingAssembly()
{
ArrayList callingAssemblies = GetCallingAssemblies();
//Loop backwards through results
for (int i = callingAssemblies.Count - 1; i > -1; i--)
{
Assembly assembly = (Assembly) callingAssemblies[i];
AssemblyName assemblyName = assembly.GetName();
string name = assemblyName.Name;
if (name != "System.Web")
return assembly;
}
return Assembly.GetExecutingAssembly();
}
QED