Get executing assembly name from referenced DLL in C# - c#

What is the best way to get the application name (i.e MyApplication.exe) of the executing assembly from a referenced class library in C#?
I need to open the application's app.config to retrieve some appSettings variables for the referenced DLL.

To get the answer to the question title:
// Full-name, e.g. MyApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
string exeAssembly = Assembly.GetEntryAssembly().FullName;
// or just the "assembly name" part (e.g. "MyApplication")
string exeAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
As mentioned by #Ben, since you mention wanting to get the configuration information, use the ConfigurationManager class.

If you want to get the current appdomain's config file, then all you need to do is:
ConfigurationManager.AppSettings....
(this requires a reference to System.Configuration of course).
To answer your question, you can do it as Ray said (or use Assembly.GetExecutingAssembly().FullName) but I think the problem is easier solved using ConfigurationManager.

To get the exact name without versions, etc. use:
string appName = Assembly.GetEntryAssembly().GetName().Name;
Works with .NET v1.1 and later.

You can get the assembly through the class type...
typeof(MyClass).Assembly

If you want the name of the parent EXE and not the referenced DLL assembly - you will need to use this:
Assembly.GetEntryAssembly().GetName().Name
This will return the EXE name (minus the .EXE part).
Using GetExecutingAssembly() is not right as per the OP's question (first paragraph of it!) as it will return the DLL name.

You should never couple your libraries to a consumer (in this case Web, WinForm or WCF app). If your library needs configuration settings, then GIVE it to the library.
Don't code the library to pull that data from a consumer's config file. Provide overloaded constructors for this (that's what they are for).
If you've ever looked at the ConfigurationManager.AppSettings object, it is simply a NameValueCollection. So create a constructor in your library to accept a NameValueCollection and have your consumer GIVE that data to the library.
//Library
public class MyComponent
{
//Constructor
public MyComponent(NameValueCollection settings)
{
//do something with your settings now, like assign to a local collection
}
}
//Consumer
class Program
{
static void Main(string[] args)
{
MyComponent component = new MyComponent(ConfigurationManager.AppSettings);
}
}

If you want to read (and display) version number:
Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
AssemblyName assname = ass.GetName();
Version ver=assname.Version;
Somewhere in application (ie Title block in a Windows form)
this.Text = "Your title Version " + ver;

For the short name of an assembly from a class instance:
Me.GetType ().Assembly.GetName().Name

Related

Is it possible to add a new dependency to a .dll without changing the source code?

I have two dotnetcore2.1 projects. First project calls a method of the second project via reflection.
using System;
using System.Reflection;
namespace experiment1
{
class Program
{
static void Main(string[] args)
{
Type _type = Type.GetType("experiment2.Program");
object _object = Activator.CreateInstance(_type);
MethodInfo info = _type.GetMethod("SecondProjectsMethod");
info.Invoke(_object, new object[]{});
}
}
}
I can't give any reference to the Second Project nor changes its code. How can I make this call successfully without adding a Reference to the First Project? I tried to add records to the first project's deps-file and execute the first program like this:
dotnet exec --depsfile experiment1.deps.json experiment1.dll
It didn't work. Is it even possible to do this by changing deps-file or any other config? Or should I manipulate .dll file somehow? Which direction I should go?
You can manually load the assembly by calling:
Assembly.Load("experiment2");
It should look for the assembly in the current folder, or use the deps file to locate it. After that, you should be able to use Type.GetType just fine.
If you want to specify the full path to the assembly, use AssemblyLoadContext.Default.LoadFromAssemblyPath instead.
You can refer to this page for more information on the different ways of loading an assembly in .net core.

Get assembly name at compile time and use it in code [duplicate]

Is there a way to find out the assembly name at design-time (i.e. not using reflection or runtime APIs such as System.Reflection.Assembly.GetEntryAssembly) from within Visual Studio?
The scenario requires a tool to get the assembly name that a Visual Studio project will eventually compile into.
This is like parsing the AssemblyName property of the .csproj - I am wondering if there are any APIs that can give this information reliably.
Please do not respond back with runtime APIs that use reflection - there is no assembly file present at the time I need the assembly name - just the metadata of the assembly in the csproj file.
if you are calling the tool via a post/pre-build event, this data is very easy to access.
Just go to the "project properties->Build Events" tab, then select either "edit pre-build" or "edit post-build", depending on when you want the tool to run. This should bring up an edit window with the ever helpful "Macros >>" button. Press this and you will be given a heap of macros to use and should be pretty much everything you need.
The "API" you could use is LINQ to XML after all the .csproj file is just xml. (and you can get the location of the .csproj file if you need from the solution file which for some reason is not XML but can be easily parsed)
You can use "TargetName" available in Macros for Post-build events. It will give you the assembly name for your project.
After a quick run through MSDN I found this article which might be a good start for some further research:
Accessing Project Type Specific Project, Project Item, and Configuration Properties
I think you will need to write some regular expression that will give you the value of "AssemblyTitle" attribute in AssemblyInfo.cs file.
Something like this:
public class Assembly
{
public static string GetTitle (string fileFullName) {
var contents = File.ReadAllText (fileFullName); //may raise exception if file doesn't exist
//regex string is: AssemblyTitle\x20*\(\x20*"(?<Title>.*)"\x20*\)
//loading from settings because it is annoying to type it in editor
var reg = new Regex (Settings.Default.Expression);
var match = reg.Match (contents);
var titleGroup = match.Groups["Title"];
return (match.Success && titleGroup.Success) ? titleGroup.Value : String.Empty;
}
}

How can I get the executing assembly version?

I am trying to get the executing assembly version in C# 3.0 using the following code:
var assemblyFullName = Assembly.GetExecutingAssembly().FullName;
var version = assemblyFullName .Split(',')[1].Split('=')[1];
Is there another proper way of doing so?
Two options... regardless of application type you can always invoke:
Assembly.GetExecutingAssembly().GetName().Version
If a Windows Forms application, you can always access via application if looking specifically for product version.
Application.ProductVersion
Using GetExecutingAssembly for an assembly reference is not always an option. As such, I personally find it useful to create a static helper class in projects where I may need to reference the underlying assembly or assembly version:
// A sample assembly reference class that would exist in the `Core` project.
public static class CoreAssembly
{
public static readonly Assembly Reference = typeof(CoreAssembly).Assembly;
public static readonly Version Version = Reference.GetName().Version;
}
Then I can cleanly reference CoreAssembly.Version in my code as required.
In MSDN, Assembly.GetExecutingAssembly Method, is remark about method "getexecutingassembly", that for performance reasons, you should call this method only when you do not know at design time what assembly is currently executing.
The recommended way to retrieve an Assembly object that represents the current assembly is to use the Type.Assembly property of a type found in the assembly.
The following example illustrates:
using System;
using System.Reflection;
public class Example
{
public static void Main()
{
Console.WriteLine("The version of the currently executing assembly is: {0}",
typeof(Example).Assembly.GetName().Version);
}
}
/* This example produces output similar to the following:
The version of the currently executing assembly is: 1.1.0.0
Of course this is very similar to the answer with helper class "public static class CoreAssembly", but, if you know at least one type of executing assembly, it isn't mandatory to create a helper class, and it saves your time.
using System.Reflection;
{
string version = Assembly.GetEntryAssembly().GetName().Version.ToString();
}
Remarks from MSDN http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getentryassembly%28v=vs.110%29.aspx:
The GetEntryAssembly method can return null when a managed assembly has been loaded from an unmanaged application. For example, if an unmanaged application creates an instance of a COM component written in C#, a call to the GetEntryAssembly method from the C# component returns null, because the entry point for the process was unmanaged code rather than a managed assembly.
Product Version may be preferred if you're using versioning via GitVersion or other versioning software.
To get this from within your class library you can call System.Diagnostics.FileVersionInfo.ProductVersion:
using System.Diagnostics;
using System.Reflection;
//...
var assemblyLocation = Assembly.GetExecutingAssembly().Location;
var productVersion = FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion
This should do:
Assembly assem = Assembly.GetExecutingAssembly();
AssemblyName aName = assem.GetName();
return aName.Version.ToString();
I finally settled on typeof(MyClass).GetTypeInfo().Assembly.GetName().Version for a netstandard1.6 app. All of the other proposed answers presented a partial solution. This is the only thing that got me exactly what I needed.
Sourced from a combination of places:
https://msdn.microsoft.com/en-us/library/x4cw969y(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/2exyydhb(v=vs.110).aspx

Why is XmlSerializer.Deserialize throwing a System.IO.FileLoadException?

I'm having a problem with XML deserialization that is baffling me.
I'm building an application that supports local customization of various services that it uses. I've implemented an abstract ServiceLocator class whose methods return various objects. Each custom installation is responsible for implementing a subclass of this and providing implementations of those methods. The meat of this class looks like this:
public abstract class ServiceLocator
{
public static void Initialize(string customFeaturesPath)
{
Assembly a = Assembly.LoadFrom(customFeaturesPath);
Type t = a.GetExportedTypes()
.AsEnumerable()
.Where(x => x.IsSubclassOf(typeof (ServiceLocator)))
.First();
Default = (ServiceLocator)a.CreateInstance(t.FullName);
}
public static ServiceLocator Default { get; private set; }
public abstract DefaultValuesContainer CreateDefaultValuesContainer();
}
This works just fine: I get the path to the custom features assembly from the application configuration file, the program calls Initialize, and then the application can call the various methods on ServiceLocator.Default and they return the appropriate custom implementations of the services.
One of these services is a DefaultValuesContainer. This is a simple object that exposes properties whose values need to be persisted in a user settings file. The idea is that I can serialize this object into a single user setting of type string. It makes for a user setting file that you wouldn't want to edit manually, but I'm cool with that.
Here's a concrete implementation of ServiceLocator.CreateDefaultValuesContainer:
protected override DefaultValuesContainer CreateDefaultValuesContainer(string serializedXml)
{
DefaultValuesContainer c = new ClientDefaultValuesContainer();
if (string.IsNullOrEmpty(serializedXml))
{
return c;
}
XmlSerializer x = new XmlSerializer(c.GetType());
return (DefaultValuesContainer) x.Deserialize(new StringReader(serializedXml));
}
Now here's the thing.
I've built unit tests for this using NUnit. When I run the tests in the test fixture class that exercises the client custom features, they work. When I run the entire test suite, the last line of the above method throws this exception:
System.InvalidOperationException : There is an error in XML document (0, 0).
----> System.IO.FileLoadException : Could not load file or assembly 'ClientCustomFeatures, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Invalid pointer (Exception from HRESULT: 0x80004003 (E_POINTER))
----> System.ArgumentNullException : Value cannot be null.
Parameter name: path1
I'm kind of baffled as to why. The SetUp method still runs, and ServiceLocator.Default still returns an object of type ClientServiceLocator, which means that it has loaded the ClientCustomFeatures assembly. Indeed, the very method that's throwing the exception is in the assembly that I'm being told can't be loaded.
What is the XmlSerializer trying to do here? Why is it trying to load an assembly that's already loaded? What on earth does "Invalid pointer" mean? And above all, how should I be debugging something like this?
If your custom assembly does not know where to load the assembly containing the ClientCustomFeatures class, this will happen. This occurs when you've deployed your custom assembly to a location that is not in the path of your main assembly and your main assembly is not in the gac. So if your custom asseblies are loaded from sub directories of your main assembly this should go away. However, if they are located in arbitrary places, you'll have a problem because they need to load your main assembly as they need access to the ClientCustomFeatures type.
I've had problems with the assembly loader (Fusion?) when one assembly loads another assembly which itself has (non-GAC) references. YourDLL.XmlSerializers.dll might be one such assembly. Try turning off Visual Studio's option to automatically generate an XML serialization assembly (Project options) - this will remove the additional assembly (and hence the dependency on it).
Fusion Log Viewer
To help diagnose assembly loading problems like these, take a look at the Fusion Log Viewer (AKA fuslogvw.exe).
Fusion == the .NET component that locates and loads assemblies.
Try to replace the line:
XmlSerializer x = new XmlSerializer(c.GetType());
with:
XmlSerializer x = new XmlSerializer(c.GetType(), new Type[] { typeof(DefaultValuesContainer), typeof(ClientDefaultValuesContainer) });

Accessing App.config in a location different from the binary

In a .NET Win console application, I would like to access an App.config file in a location different from the console application binary. For example, how can C:\bin\Text.exe get its settings from C:\Test.exe.config?
using System.Configuration;
Configuration config =
ConfigurationManager.OpenExeConfiguration("C:\Test.exe");
You can then access the app settings, connection strings, etc from the config instance. This assumes of course that the config file is properly formatted and your app has read access to the directory. Notice the path is not "C:\Test.exe.config" The method looks for a config file associated with the file you specify. If you specify "C:\Test.exe.config" it will look for "C:\Test.exe.config.config" Kinda lame, but understandable, I guess.
Reference here: http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx
It appears that you can use the AppDomain.SetData method to achieve this. The documentation states:
You cannot insert or modify system entries with this method.
Regardless, doing so does appear to work. The documentation for the AppDomain.GetData method lists the system entries available, of interest is the "APP_CONFIG_FILE" entry.
If we set the "APP_CONFIG_FILE" before any application settings are used, we can modify where the app.config is loaded from. For example:
public class Program
{
public static void Main()
{
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", #"C:\Temp\test.config");
//...
}
}
I found this solution documented in this blog and a more complete answer (to a related question) can be found here.
Use the following (remember to include System.Configuration assembly)
ConfigurationManager.OpenExeConfiguration(exePath)
You can set it by creating a new app domain:
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ConfigurationFile = fileLocation;
AppDomain add = AppDomain.CreateDomain("myNewAppDomain", securityInfo, domainSetup);
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ConfigurationFile = #"D:\Mine\Company\";
string browserName = ConfigurationManager.AppSettings["browser"];

Categories