C# Getting Parent Assembly Name of Calling Assembly - c#

I've got a C# unit test application that I'm working on. There are three assemblies involved - the assembly of the C# app itself, a second assembly that the app uses, and a third assembly that's used by the second one.
So the calls go like this:
First Assembly ------> Second Assembly---------> Third Assembly.
What I need to do in the third assembly is get the name of the Fist Assembly that called the second assembly.
Assembly.GetExecutingAssembly().ManifestModule.Name
Assembly.GetCallingAssembly().ManifestModule.Name
returns the name of the Second assembly.
and
Assembly.GetEntryAssembly().ManifestModule.Name
return NULL
Does anybody know if there is a way to get to the assembly name of the First Assembly?
As per the other users demand here I put the code. This is not 100% code but follow of code like this.
namespace FirstAssembly{
public static xcass A
{
public static Stream OpenResource(string name)
{
return Reader.OpenResource(Assembly.GetCallingAssembly(), ".Resources." + name);
}
}
}
using FirstAssembly;
namespace SecondAssembly{
public static class B
{
public static Stream FileNameFromType(string Name)
{
return = A.OpenResource(string name);
}
}
}
and Test project method
using SecondAssembly;
namespace ThirdAssembly{
public class TestC
{
[TestMethod()]
public void StremSizTest()
{
// ARRANGE
var Stream = B.FileNameFromType("ValidMetaData.xml");
// ASSERT
Assert.IsNotNull(Stream , "The Stream object should not be null.");
}
}
}

I guess you should be able to do it like this:
using System.Diagnostics;
using System.Linq;
...
StackFrame[] frames = new StackTrace().GetFrames();
string initialAssembly = (from f in frames
select f.GetMethod().ReflectedType.AssemblyQualifiedName
).Distinct().Last();
This will get you the Assembly which contains the first method which was started first started in the current thread. So if you're not in the main thread this can be different from the EntryAssembly, if I understand your situation correctly this should be the Assembly your looking for.
You can also get the actual Assembly instead of the name like this:
Assembly initialAssembly = (from f in frames
select f.GetMethod().ReflectedType.Assembly
).Distinct().Last();
Edit - as of Sep. 23rd, 2015
Please, notice that
GetMethod().ReflectedType
can be null, so retrieving its AssemblyQualifiedName could throw an exception.
For example, that's interesting if one wants to check a vanilla c.tor dedicated only to an ORM (like linq2db, etc...) POCO class.

This will return the the initial Assembly that references your currentAssembly.
var currentAssembly = Assembly.GetExecutingAssembly();
var callerAssemblies = new StackTrace().GetFrames()
.Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
.Where(x => x.GetReferencedAssemblies().Any(y => y.FullName == currentAssembly.FullName));
var initialAssembly = callerAssemblies.Last();

It worked for me using this:
System.Reflection.Assembly.GetEntryAssembly().GetName()

Assembly.GetEntryAssembly() is null if you run tests from nunit-console too.
If you just want the name of the executing app then use:
System.Diagnostics.Process.GetCurrentProcess().ProcessName
or
Environment.GetCommandLineArgs()[0];
For nunit-console you would get "nunit-console" and "C:\Program Files\NUnit 2.5.10\bin\net-2.0\nunit-console.exe" respectively.

Try:
Assembly.GetEntryAssembly().ManifestModule.Name
This should be the assembly that was actually executed to start your process.

Not completely sure what you're looking for, especially as when running in the context of a unit test you'll wind up with:
mscorlib.dll
Microsoft.VisualStudio.TestPlatform.Extensions.VSTestIntegration.dll
(or something similar depending on your test runner) in the set of assemblies that lead to any method being called.
The below code prints the names of each of the assemblies involved in the call.
var trace = new StackTrace();
var assemblies = new List<Assembly>();
var frames = trace.GetFrames();
if(frames == null)
{
throw new Exception("Couldn't get the stack trace");
}
foreach(var frame in frames)
{
var method = frame.GetMethod();
var declaringType = method.DeclaringType;
if(declaringType == null)
{
continue;
}
var assembly = declaringType.Assembly;
var lastAssembly = assemblies.LastOrDefault();
if(assembly != lastAssembly)
{
assemblies.Add(assembly);
}
}
foreach(var assembly in assemblies)
{
Debug.WriteLine(assembly.ManifestModule.Name);
}

If you know the number of frame in the stack, you can use the StackFrame object and skip the number of previous frame.
// You skip 2 frames
System.Diagnostics.StackFrame stack = new System.Diagnostics.StackFrame(2, false);
string assemblyName = stack.GetMethod().DeclaringType.AssemblyQualifiedName;
But, if you want the first call, you need to get all frames and take the first. (see AVee solution)

How about Assembly.GetEntryAssembly()? It returns the main executable of the process.
Process.GetCurrentProcess().MainModule.ModuleName should also return about the same as the ManifestModule name ("yourapp.exe").

This works for getting the original assembly when using two assemblies in an NUnit test, without returning a NULL. Hope this helps.
var currentAssembly = Assembly.GetExecutingAssembly();
var callerAssemblies = new StackTrace().GetFrames()
.Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
.Where(x => x.GetReferencedAssemblies().Any(y => y.FullName == currentAssembly.FullName));
var initialAssembly = callerAssemblies.Last();

Related

Cannot get types from assembly after ReflectionOnlyLoadFrom

I have consulted code on the website http://codeproject.com with the title "Loading Assemblies from Anywhere into a New AppDomain" of Marius Bancila, but I tested the error as in the attached picture, currently, I don't know resolve, hope you help, thank you.
Link Code
https://www.codeproject.com/Articles/453778/Loading-Assemblies-from-Anywhere-into-a-New-AppDom#_articleTop
Test
public class Program
{
[STAThread]
public static void Main()
{
var project = #"D:\Github\BeyConsPlugin\BeyConsProject\bin\x64\Debug\BeyConsRevitProject.dll";//Path to assembly
var manager = new AssemblyReflectionManager();
var success = manager.LoadAssembly(project, Guid.NewGuid().ToString());
if (success)
{
var result = manager.Reflect(project, (a) =>
{
return a.GetTypes();
});
Console.WriteLine(string.Join("\n", result.Select(x => x.Name)));
}
Console.ReadKey();
manager.UnloadAssembly(project);
}
}
Error
Assembly Resolver not Set
Marius's code has a bug in AssemblyReflectionProxy with regards that the Assembly Resolver is not set if you call LoadAssembly unlike Reflect<> which does.
Depending on how a child app domain is created, when loading assemblies it might only have access to the folder as specified during creation. If you need to assembly probe elsewhere for the assembly or its dependencies you need a Assembly Resolver. When .NET is looking for an assembly for a domain, it will call your handler as specified in the assemblie's ReflectionOnlyAssemblyResolve event. If not specified or if the resolver fails to locate the assembly, it will bubble up and throw a load fail exception.
I suggest you change the code from:
public class AssemblyReflectionProxy : MarshalByRefObject
{
private string _assemblyPath;
public void LoadAssembly(String assemblyPath)
{
try
{
_assemblyPath = assemblyPath;
Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
catch (FileNotFoundException)
{
// Continue loading assemblies even if an assembly
// cannot be loaded in the new AppDomain.
}
}
...to:
public class AssemblyReflectionProxy : MarshalByRefObject
{
private string _assemblyPath;
public void LoadAssembly(String assemblyPath)
{
try
{
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve // <---- add me
+= OnReflectionOnlyResolve;
_assemblyPath = assemblyPath;
Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
catch (FileNotFoundException)
{
// Continue loading assemblies even if an assembly
// cannot be loaded in the new AppDomain.
}
}
You can see this in Sacha's original code that on which Marius based his.
Add Provision for Resolve Paths
The other problem with the code is that both assume that when loading one assembly, any dependent assemblies are in the same folder something that may not always be the case.
Alter AssemblyReflectionProxy to include a list of paths in which to probe:
public List<string> ResolvePaths { get; set; }
Then modify OnReflectionOnlyResolve to resemble the following:
private Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory)
{
Assembly loadedAssembly =
AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()
.FirstOrDefault(
asm => string.Equals(asm.FullName, args.Name,
StringComparison.OrdinalIgnoreCase));
if (loadedAssembly != null)
{
return loadedAssembly;
}
foreach (var tryFolder in ResolvePaths)
{
var asmName = args.Name.Split(',');
var assemblyPath = Path.Combine(tryFolder, asmName[0] + ".dll");
if (!File.Exists(assemblyPath))
return null;
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
}
What's in a name?
Both articles neglected to point out the fine print when using ReflectionOnlyLoad. Though Sacha did at least mention his code was for a "code generator" I can't help but wonder that both articles with their "Loading Assemblies....into a New AppDomain" are perhaps somewhat subject to interpretation.
The aim of ReflectionOnlyLoad is just that - for reflection. If you load an assembly via this method you cannot execute any code in it. Additionally and somewhat surprising at first to most assembly reflector programmers including me is that calling GetCustomAttributes will also fail (because it attempts to "instantiate" types in the assembly).
If you are writng your own plug-in system in which each plug-in has its own App Domain, the Assembly reflection and load methods are useful for different stages of the plug-in system loading pipeline:
first pass - use ReflectionOnlyLoad as a way to inspect the plug-in to see if it is valid; perhaps you want to run some security checks safe in the knowledge that none of the plug-ins code can run during this phase
second pass - after verifying the plug-in, you can safely Load/LoadFrom the assembly and execute the code

.NET Fetch all exception in 3rd party app

We are integrating with a 3rd party application by supplying a file they can import. The file contains many properties(+100) , not all of them are mandatory, we only need a few. However, the application keeps crashing(gently, with an alert due to big try catch) with 'object not set to a reference ...' without a stacktrace. So at some place the 3rd party app is not verifying some optional parameters on nulls causing the crash. Searching what property is searching for a needle in a haystack.
Is it possible somehow to monitor all exceptions of an application we don't have the source of even if they are caught? This so we can get the stacktrace and check with Ilspy what property is causing the problem.
The 3rd party app is from a relatively big company. We cannot just communicate with their developers.
You could try:
Assembly otherAssembly = typeof(/* a class of the other assembly */).Assembly;
AppDomain.CurrentDomain.FirstChanceException += (sender, fceea) =>
{
AppDomain domain = (AppDomain)sender;
var method = fceea.Exception.TargetSite;
var declaringType = method.DeclaringType;
var assembly = declaringType.Assembly;
if (assembly == otherAssembly)
{
// Log the stacktrace of the Exception, or whatever
// you want
}
};
This will let you see all the Exceptions (even those catched). You have to put this code where the program starts (or even in other places it is ok, but try to not execute it multiple times, because the event is AppDomain-wide)
Note that considering how the stack trace inside an exception is handled, perhaps it's better to:
if (assembly == otherAssembly)
{
// Log the stacktrace st of the Exception, or whatever
// you want
string st = new StackTrace(1, true).ToString();
}
so that you can see the full stack trace.
Now, as I've suggested you, you could write a small Console app/Winforms app, Add Reference to the other exe (yes, you can add as a reference another .exe if that is written in .NET :-) ), and in your Main do something like:
var otherAssembly = typeof(/* Some type from the other assembly */).Assembly;
// We look all the classes in an assembly for a static Main() that has
// the "right" signature
var main = (from x in otherAssembly.GetTypes()
from y in x.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
where y.Name == "Main" && (y.ReturnType == typeof(int) || y.ReturnType == typeof(void)) && y.GetGenericArguments().Length == 0
let parameters = y.GetParameters()
where parameters.Length == 0 || (parameters.Length == 1 && parameters[0].ParameterType == typeof(string[]))
select y).Single();
if (main.GetParameters().Length == 0)
{
// static Main()
main.Invoke(null, null);
}
else
{
// static Main(string[] args)
// Note that new string[0] is the string[] args!
// You can pass *your* string[] args :-)
// Or build one however you want
main.Invoke(null, new object[] { new string[0] });
}
to invoke the other Main(). Clearly before doing this, you have to setup the FirstChanceException handler

Method import using Mono.Cecil

Help me please with method import.
I want to weave assembly and inject method call reference from base class defined in the other assembly (in fact it's the assembly where weaving code is defined).
private void InsertCallSetReference()
{
//Get the load instruction to replace
var ilProcessor = Property.SetMethod.Body.GetILProcessor();
var argumentLoadInstructions = ilProcessor.Body.Instructions.ToList();
MethodReference methodReference = ImportMethod("SetReference");
foreach (var instruction in argumentLoadInstructions)
{
if (instruction.OpCode == OpCodes.Stfld)
{
ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Call, methodReference));
ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Ldarg_1));
ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Ldstr, DBFieldName));
ilProcessor.InsertAfter(instruction, ilProcessor.Create(OpCodes.Ldarg_0));
ilProcessor.Remove(instruction);
break;
}
}
}
Method import code works just fine and returns method reference
private MethodReference ImportMethod(string name)
{
var type = MongoConnectModule.Import(typeof(BaseDataObject));
return MongoConnectModule.Import(type.Resolve().Methods.First(m => m.Name == name));
}
But after AssemblyDefinition Write call it throws me an error:
C:\dev\MongoConnect\WeavingTaskTest\Weaving\CodeWeaving.targets(32,5):
error MSB4018: System.ArgumentException: Member 'System.Void
MongoConnect.BaseDataObject::SetProperty(System.String,System.Object)'
is declared in another module and needs to be imported
_assemblyDefinition.Write(_assemblyPath, new WriterParameters() { WriteSymbols = true, SymbolWriterProvider = debugWriterProvider });
Any idea how I could do that?
I've found the solution.
The reason was really funny.
Module.Import() method must be called from current module we want to modify, not the module where method is defined. It is not clear from original docs.
For example, we want to add some method defined in the Referenced.dll assembly to our Main.dll assembly. Then we have to find main module of our Main.dll assembly and then call MainModule.Import(methodFromReferencedAssembly);

How to figure out dynamically all methods with custom attribute

I have a simple challenge. I dynamically need to figure out all methods with a specific attribute in C#. I'm going to load the assemblies dynamically from another application and need to find out the exact methods. The assemblies look like the followings:
Base.dll:
Class Base
{
[testmethod]
public void method1()
...
}
Derived.dll:
Class Derived:Base
{
[testmethod]
public void method2()
}
Now in 3rd application I dynamically like to load the above mentioned dlls and find out testmethods.
If I load Base.dll, I need to get testmethod1. If I load Drived.dll, should I get testmethod1 and testmethod2.
I found some code online which helped me to load dlls dynamically:
List<Assembly> a = new List<Assembly>();
string bin = #"Bin-Folder";
DirectoryInfo oDirectoryInfo = new DirectoryInfo(bin);
//Check the directory exists
if (oDirectoryInfo.Exists)
{
//Foreach Assembly with dll as the extension
foreach (FileInfo oFileInfo in oDirectoryInfo.GetFiles("*.dll", SearchOption.AllDirectories))
{
Assembly tempAssembly = null;
//Before loading the assembly, check all current loaded assemblies in case talready loaded
//has already been loaded as a reference to another assembly
//Loading the assembly twice can cause major issues
foreach (Assembly loadedAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
//Check the assembly is not dynamically generated as we are not interested in these
if (loadedAssembly.ManifestModule.GetType().Namespace != "System.Reflection.Emit")
{
//Get the loaded assembly filename
string sLoadedFilename =
loadedAssembly.CodeBase.Substring(loadedAssembly.CodeBase.LastIndexOf('/') + 1);
//If the filenames match, set the assembly to the one that is already loaded
if (sLoadedFilename.ToUpper() == oFileInfo.Name.ToUpper())
{
tempAssembly = loadedAssembly;
break;
}
}
}
//If the assembly is not aleady loaded, load it manually
if (tempAssembly == null)
{
tempAssembly = Assembly.LoadFrom(oFileInfo.FullName);
}
a.Add(tempAssembly);
}
The above code is working fine and I can load the DLLs. However when I use the following code to find out the right method, it doesn't return any desired results. I'm wondering which part is not correct. The following code lists about 145 methods but non of them is one which I'm looking for.
public static List<string> GetTests(Type testClass)
{
MethodInfo[] methodInfos = testClass.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance);
Array.Sort(methodInfos,
delegate(MethodInfo methodInfo1, MethodInfo methodInfo2)
{ return methodInfo1.Name.CompareTo(methodInfo2.Name); });
foreach (MethodInfo mi in methodInfos)
{
foreach (var item in mi.GetCustomAttributes(false))
{
if
(item.ToString().CompareTo("Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute") == 0)
result.Add(mi.Name);
}
}
return result;
}
Can any one help me with this issue?
I'm not sure why but I tried to instantiate objects from above mentioned classes (Base and Derived) and the above mentioned code returns the right results. However as mentioned above if I don't have an object from base and derived classes and try to figure out the methods based on the types, it doesn't return the desired results.
Thx
The simplest approach is to use MethodInfo.IsDefined - quite possibly with LINQ as well:
var testMethods = from assembly in assemblies
from type in assembly.GetTypes()
from method in type.GetMethods()
where method.IsDefined(typeof(TestMethodAttribute))
select method;
foreach (var method in testMethods)
{
Console.WriteLine(method);
}
(I'd do all the sorting with LINQ as well. Obviously you can tune the GetMethods call etc to only return instance methods, for example.)
It's not entirely clear to me why your current approach doesn't work or why it does work when you've created instances - but without a short but complete example demonstrating the problem, it would be hard to diagnose it further. I'd definitely start with the code above :)

Load types that inherit a certain Interface from assemblies in bin

I am working on code for an ASP.NET MVC application that will do the following when the application is started:
Load all assemblies in the application bin directory
Get all types from each assembly that are derived from an interface (ITask)
Invoke the Execute() method on each type
Here is the current idea I came up with. This method will get called in OnApplicationStarted():
private void ExecuteTasks()
{
List<ITask> startupTasks = new List<ITask>();
Assembly asm = this.ExecutingAssembly;
// get path of executing (bin) folder
string codeBase = this.ExecutingAssembly.CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
string bin = Path.GetDirectoryName(path);
string[] assemblies = Directory.GetFiles(bin, "*.dll");
foreach (String file in assemblies)
{
try
{
if (File.Exists(file))
{
// load the assembly
asm = Assembly.LoadFrom(file);
// get all types from the assembly that inherit ITask
var query = from t in asm.GetTypes()
where t.IsClass &&
t.GetInterface(typeof(ITask).FullName) != null
select t;
// add types to list of startup tasks
foreach (Type type in query)
{
startupTasks.Add((ITask)Activator.CreateInstance(type));
}
}
}
catch (Exception ex)
{
Exceptions.LogException(ex);
}
}
// execute each startup task
foreach (ITask task in startupTasks)
{
task.Execute();
}
}
My question: is there a better way to do any of these steps? The method to get the bin directory was taken from this answer: https://stackoverflow.com/a/283917/213159. It seems like a lot of work to do something simple, but I couldn't figure out an easier approach.
Also, is using System.Activator to create instances and then subsequently invoke the Execute() method on each instance the most efficient way to perform that step?
You may be able to clean the code up, but without any extension libraries the code doesn't get all that much shorter.
About performance, I'd not worry too much about optimizing OnApplicationStarted tasks in particular, it's hopefully not called all that often and shouldn't impact your site once it's up and running.

Categories