40

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.");
        }
}
}
Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Saroop Trivedi
  • 2,245
  • 6
  • 31
  • 49

9 Answers9

42

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.

Community
  • 1
  • 1
AVee
  • 3,348
  • 17
  • 17
  • This is a great answer! Really helped me get to what I needed – Piotr Kula Oct 15 '15 at 08:51
  • 2
    Why do you need `.Distinct()` if you follow with `.Last()`? – Dorus Apr 16 '18 at 16:03
  • @Dorus because you could (will?) get a wrong result otherwise, e.g. I got `mscorlib` without `.Distinct()`. – Jack Miller Nov 02 '18 at 11:49
  • @JackMiller That seems very strange to me, actually as if the last frame is `mscorlib` and your stack is something like `aba` where the second `a` is filtered out by distinct and `last` then takes the `b`. – Dorus Nov 12 '18 at 08:39
  • I totally agree with you. It IS very strange. On the other hand I did not try to find out how `.Distinct()` actually works. – Jack Miller Nov 12 '18 at 12:14
  • Worked well with synchronous calls. With async code, the stack seen in GetFrames() doesn't match where the async execution resumed from so I don't see who actually called. VS debugger is able to tell where the async execution resumed from, so there is a way to figure out who start the async execution. Anyone knows how to tweak the solution to also work with async callers? – David Burg May 06 '21 at 17:56
16

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();
realstrategos
  • 783
  • 8
  • 7
13

It worked for me using this:

System.Reflection.Assembly.GetEntryAssembly().GetName()
Marcello
  • 1,099
  • 14
  • 18
7

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.

tymtam
  • 31,798
  • 8
  • 86
  • 126
3

Try:

Assembly.GetEntryAssembly().ManifestModule.Name

This should be the assembly that was actually executed to start your process.

Jon Egerton
  • 40,401
  • 11
  • 97
  • 129
0

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);
}
mlorbetske
  • 5,529
  • 2
  • 28
  • 40
  • I know all unit test rule. Now my point is I don't want to read all assembly. Simply I want A reference in C. This thing make my code complex. – Saroop Trivedi Jun 21 '12 at 10:03
0

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)

Hyralex
  • 990
  • 1
  • 8
  • 25
-1

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").

Botz3000
  • 39,020
  • 8
  • 103
  • 127
  • Ah, the manifestmodule name returns null, how about: Assembly.GetEntryAssembly().FullName (or GetName() depending on your needs) – Me.Name Jun 13 '12 at 12:03
  • @sarooptrivedi I added another option. – Botz3000 Jun 13 '12 at 12:09
  • @Botz3000:I used this calling of Assembly in unittest project. – Saroop Trivedi Jun 13 '12 at 12:17
  • @sarooptrivedi What kind of unit test? If the assemblies are loaded by native code (not sure how your unit testing framework is set up), GetEntryAssembly() will return null. Did you try the second option already? – Botz3000 Jun 13 '12 at 12:22
  • @Botz3000: I have some resources files in Test project. I don't want to deploy all files through the DeploymentItem.So I create one project inwhich I use that all files in my unit test with help of creating one test helper project B.But the Assembly calling project is in some another helper project C. So When I get the Assembly reference of Unit test project into Project C then for GetEntryAssembly() it's return NULL. – Saroop Trivedi Jun 15 '12 at 12:29
  • @sarooptrivedi If you use MStest you can add items, that should be deployed for all tests, to your testsettings-file. – habakuk Jun 26 '12 at 15:18
-4

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();