why reflection.assembly loadfile doesn't load all dlls? - c#

I am using LoadFrom(), to load dlls, but for some reason this load function doesn't work on all dlls,
i want to load 3000 dlls to get from each one the copyright attribute.
my code :
class ReverseDLL
{
private Assembly assembly;
private AssemblyDescriptionAttribute desc;
private AssemblyTitleAttribute title;
private AssemblyCopyrightAttribute copyRight;
public string getCopyright(string path)
{
try
{
//assembly = System.Reflection.Assembly.Load(System.IO.File.ReadAllBytes(path));
assembly = System.Reflection.Assembly.LoadFrom(path);//"C:\\Windows\\winsxs\\x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.30729.1_none_bb1f6aa1308c35eb\\msvcm90d.dll");//path);// LoadFrom(path);
desc = (AssemblyDescriptionAttribute)
AssemblyDescriptionAttribute.GetCustomAttribute(
assembly, typeof(AssemblyDescriptionAttribute));
title = (AssemblyTitleAttribute)
AssemblyTitleAttribute.GetCustomAttribute(
assembly, typeof(AssemblyTitleAttribute));
copyRight = (AssemblyCopyrightAttribute)AssemblyCopyrightAttribute.GetCustomAttribute(assembly, typeof(AssemblyCopyrightAttribute));
}
catch
{
this.copyRight = new AssemblyCopyrightAttribute("");
}
if (this.copyRight == null)
this.copyRight = new AssemblyCopyrightAttribute("");
return copyRight.Copyright;
}
}

I don't know about the reflection problem without you providing more info (such as the error), but you could also try access the file itself:
string copyright = FileVersionInfo.GetVersionInfo(path).LegalCopyright;
This accesses the file-system meta-data (like you would see in explorer), and has the advantage of working for both managed and unmanaged dlls; but it requires that meta-data to exist (it doesn't look at the attribute).
Edit: a quick check indicates that (as expected) the compiler does check for this attribute and populate the file meta-data correctly.

Have you tried stopping on exceptions? Ctrl + Alt + E, stop on framework exceptions when they are thrown. The exception message should give you some information as to why the DLL couldn't be loaded.

Using reflection is not the optimal approach, as some of the dll may have dependencies you don't have.
Using a metadata parser can give you the things you want,
http://ccimetadata.codeplex.com/
http://www.mono-project.com/Cecil
The way Marc mentioned does not work for most .NET specific metadata.

Related

MEF doesn´t load DLL

We fighted multiple days with MEF which doesn´t load a specific DLL.
2018-12-10 09:58:32,762 [5] ERROR RfcServer.RfcServer The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) No exports were found that match the constraint:
ContractName RfcServer.Definitions.ICryptManager
RequiredTypeIdentity RfcServer.Definitions.ICryptManager
First we enhanced our Application in such away that we used a CustomRefelctionContext to log which types will be "seen" from MEF:
public class CatalogFilter : CustomReflectionContext
{
protected override IEnumerable<object> GetCustomAttributes(MemberInfo member, IEnumerable<object> declaredAttributes)
{
var memberName = member.ToString();
var hasExportAttribute = declaredAttributes.FirstOrDefault(f => f is ExportAttribute) != null;
// Log member name
Console.WriteLine(memberName);
// Default: No change
return base.GetCustomAttributes(member, declaredAttributes);
}
}
An instance of this was given to DirectoryCatalog (CustomReflectionContext). Based on output we come to know our Application does not load a dll.
We solved
We provided our Application to another department via zip file in a mail. After extract the files some (not all!) DLLs are marked as "unsafe" and you need to unblock those files:
Unblock a DLL
The issue was solved by unblock Dlls. In the file properties you can click "unblock".

Is it possible to get assembly info at compile time without reflection?

It is trivial to get Assembly information at run-time using reflection:
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
However, I cannot use reflection in my project due to restricted execution environment. In limited trust environment this code will not work.
I want to use some attributes from AssemblyInfo.cs at compile time to show product name, version etc. without invoking reflection mechanism.
Most primitive way would be just duplicating strings from AssemblyInfo.cs file as constant strings somewhere else. But maybe there exist some more elegant solutions?
Of course, some essential info on assembly can be properly resolved only at run-time through reflection. Say, assembly path, execution context etc. But info about name and version is written in project code and should be normally available at compile time.
Any comments and ideas are appreciated. Thank you.
Since nobody posted an answer so far, I will publish a variant, to which I came based on comments to the question. As #Julo advised, I took way exactly opposite to getting info from attributes and, instead, decided for constant definitions in a class:
public class Resource
{
public const string VERSION = "1.0.0.0";
public const string COMPANY = "Company";
public const string APPICATION = "App";
}
Then I pass these values to assembly attributes:
[assembly: AssemblyTitle(Resource.APPICATION)]
[assembly: AssemblyCompany(Resource.COMPANY)]
[assembly: AssemblyVersion(Resource.VERSION)]
[assembly: AssemblyFileVersion(Resource.VERSION)]
Of course, I can also access these in my code at compile time:
string tool = null, version = null;
//System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
//System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
//if (string.IsNullOrEmpty(tool) && fvi != null) tool = fvi.ProductName;
//if (string.IsNullOrEmpty(version) && fvi != null) version = fvi.FileVersion;
tool = Resource.APPICATION;
version = Resource.VERSION;
Drawback here can be that automatic version increment tools in build environments will not be able to access these constants. Advantage can be that constants can be shared between many projects as a single file to enable cetralised version management for the whole solution.

How to read names and versions of assemblies

I have to create an application to read the name of all DLLs (assemblies) in my application path along with its version. And also to read the same of all the dll in the sub folders.
How to do this in C#. Can any one help me with sample code?
EDIT : how to read details of Legacy dlls( External dlls- not created in .NET)
Thanks in advance.
You should search through your given root directory by calling Directory.GetFiles(). You can run through the result and load every assembly by calling Assembly.ReflectionOnlyLoadFrom() (cause if you load it that way it won't be added to the AppDomain, thous no unload is needed).
With these Assembly classes you can access the GetName() function and take a look into the Version property to get the version information.
Other properties, that are not easily to get, can be reached through the GetCustomAttribute() function like this:
((AssemblyCopyrightAttribute)assembly.GetCustomAttribute(typeof(AssemblyCopyrightAttribute), true).Copyright
With these informations you should be able to built up the list you like.
Update:
And here's the obligatory linq code sample:
var rootPath = #"C:\MyRoot\Folder";
var query = Directory.GetFiles(rootPath, "*.dll", SearchOption.AllDirectories)
.Select(fileName =>
{
try
{
return Assembly.ReflectionOnlyLoadFrom(fileName);
}
catch
{
return null;
}
})
.Where(assembly => assembly != null)
.Select(assembly => new
{
Version = assembly.GetName().Version.ToString(),
Name = assembly.GetName().Name
});
foreach (var infos in query)
{
Console.WriteLine(infos.Name + " " + infos.Version);
}
Update 2:
So to get it from normal DLLs you should take a look into this question.
I'm a bit confused on what you actually want, but check the Assembly class: http://msdn.microsoft.com/en-us/library/system.reflection.assembly.aspx
Use Assembly.Load. There is one problem, you can't unload it, so if you do it too much times your memory will be filled by garbage.
If you call AssemblyName.GetAssemblyName, the assembly doesn't get loaded into your appdomain.
To include subfolders, you'll likely need to write a recursive function. Directory.GetDirectories or DirectoryInfo.GetDirectories can be used to retrieve all subfolders.
Use Assembly.GetName() to get an object, where you can extract the assembly version, as one part of an assemblies name is its version.
As already mentioned above, an assembly loaded with Assembly.Load cannot be unloaded and therefore remains in memory. You can however create a separate AppDomain, which you can unload again. Data transfer between AppDomains is possible by passing serializable objects, which is no problem for you because you just want to pass a string.
If you actually want to load the assemblies in the context of an extendable application, have a look at MEF.
Best Regards,
Oliver Hanappi
Use Assembly.ReflectionOnlyLoadFrom if you don't need to execute any code from that assembly and you want only gather some info about members contained inside.

Assembly.GetTypes() - ReflectionTypeLoadException

We implement a plugin framework for our application and load plugin assemblies using Assembly.Loadfrom. We then use GetTypes() and further examine the types with each plugin file for supported Interfaces.
A path for the plugins is provided by the user and we cycle through each of the files in the folder to see if it (the plugin) supports our plugin interface. If it does, we create an instance, if not we move onto the next file.
We build two versions of software from the one code base (appA_1 and appA_2).
Loading the plugins works well when the plugins are loaded by the application that was built at the same time as the plugin file. However if we build appA_2 and point to the plugin folder of appA_1, we get an exception when GetTypes() is called.
A basic version of our code is;
var pluginAssembly = Assembly.LoadFrom(FileName);
foreach (var pluginType in pluginAssembly.GetTypes())
{
We get a "ReflectionTypeLoadException" exception.
This is concerning because we want our application to be able to load the types of any plugin, built by anyone. Is there something we are missing?
EDIT:
After iterating through the LoaderExceptions we have discovered that there is a single file libPublic.dll that generates a System.IO.FileNotFoundException exception. The strange thing is that this file resides in the application directory and the plugin is referenced to the project file.
EDIT 2:
In the exception log we find the following
"Comparing the assembly name resulted in the mismatch: Revision Number"
A few things:
Make sure you don't have duplicate assemblies in the plugin directory (i.e. assemblies that you're already loading in your main app from your app directory.) Otherwise, when you load your plugin, it may load an additional copy of the same assembly. This can lead to fun exceptions like:
Object (of type 'MyObject') is not of type 'MyObject'.
If you're getting the exception when instantiating a type, you may need to handle AppDomain.AssemblyResolve:
private void App_Startup(object sender, StartupEventArgs e)
{
// Since we'll be dynamically loading assemblies at runtime,
// we need to add an appropriate resolution path
// Otherwise weird things like failing to instantiate TypeConverters will happen
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var domain = (AppDomain) sender;
foreach (var assembly in domain.GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
}
I realize it's a bit strange to have to tell the CLR that, in order to resolve an assembly, find the assembly with the name we're using to resolve, but I've seen odd things happen without it. For example, I could instantiate types from a plugin assembly, but if I tried to use TypeDescriptor.GetConverter, it wouldn't find the TypeConverter for the class, even though it could see the Converter attribute on the class.
Looking at your edits, this is probably not what's causing your current exception, though you may run into these issues later as you work with your plugins.
Thanks to this post I could solve the ReflectionTypeLoadException that I was getting in a UITypeEditor. It's a designer assembly (a winforms smart-tag used at design-time) of a custom class library, that scan for some types.
/// <summary>
/// Get the types defined in the RootComponent.
/// </summary>
private List<Type> getAssemblyTypes(IServiceProvider provider)
{
var types = new List<Type>();
try
{
IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
foreach (var assembly in ((AppDomain)sender).GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
};
Type rootComponentType = resolution.GetType(host.RootComponentClassName, false);
types = rootComponentType.Assembly.GetTypes().ToList();
}
catch
{
}
return types;
}
You are getting an assembly version mismatch. Since your plugins refer to this libPublic.dll, you must version it carefully and in particular not bump its revision/build/etc. numbers at every compile.

Using the Web Application version number from an assembly (ASP.NET/C#)

How do I obtain the version number of the calling web application in a referenced assembly?
I've tried using System.Reflection.Assembly.GetCallingAssembly().GetName() but it just gives me the dynamically compiled assembly (returning a version number of 0.0.0.0).
UPDATE: In my case I needed a solution that did not require a reference back to a class within the web application assembly. Jason's answer below (marked as accepted) fulfils this requirement - a lot of others submitted here don't.
Here is some code I use that supports getting the application's "main" assembly from either Web or non-web apps, you can then use GetName().Version to get the version.
It first tries GetEntryAssembly() for non-web apps. This returns null under ASP.NET.
It then looks at HttpContext.Current to determine if this is a web application. It then uses the Type of the current HttpHandler - but this type's assembly might be a generated ASP.NET assembly if the call is made from with an ASPX page, so it traverses the HttpHandler's BaseType chain until it finds a type that isn't in the namespace that ASP.NET uses for its generated types ("ASP").
This will usually be a type in your main assembly (eg. The Page in your code-behind file). We can then use the Assembly of that Type.
If all else fails then fall back to GetExecutingAssembly().
There are still potential problems with this approach but it works in our applications.
private const string AspNetNamespace = "ASP";
private static Assembly getApplicationAssembly()
{
// Try the EntryAssembly, this doesn't work for ASP.NET classic pipeline (untested on integrated)
Assembly ass = Assembly.GetEntryAssembly();
// Look for web application assembly
HttpContext ctx = HttpContext.Current;
if (ctx != null)
ass = getWebApplicationAssembly(ctx);
// Fallback to executing assembly
return ass ?? (Assembly.GetExecutingAssembly());
}
private static Assembly getWebApplicationAssembly(HttpContext context)
{
Guard.AgainstNullArgument(context);
object app = context.ApplicationInstance;
if (app == null) return null;
Type type = app.GetType();
while (type != null && type != typeof(object) && type.Namespace == AspNetNamespace)
type = type.BaseType;
return type.Assembly;
}
UPDATE:
I've rolled this code up into a small project on GitHub and NuGet.
I find that the simplest one-liner way to get the version of your "main" assembly (instead of the dynamic one) is:
typeof(MyMainClass).Assembly.GetName().Version
Use your top-level class, which isn't likely to ever "change its meaning" or to be replaced as part of a refactoring effort, as MyMainClass. You know in which assembly this very class is defined and there can no longer be confusion as to where the version number comes from.
I prefer the Web.Config to store the current version of the site.
You can also try create an AssemblyInfo.cs file in the web application root that has the following:
using System.Reflection;
using System.Runtime.CompilerServices;
...
[assembly: AssemblyVersion("1.0.*")]
...
then access the value via the code like this:
System.Reflection.Assembly.GetExecutingAssembly()
Here is more informaiton on the AssemblyInfo class.
To add to the responders that have already posted. In order to get the assembly version in an ASP.Net web application you need to place a method in the code behind file similar to:
protected string GetApplicationVersion() {
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
In the ASPX page you want to display the version number simply place:
<%= GetApplicationVersion() %>
Just in case anyone is still interested; this should do the trick and should be a tad safer than just taking the BaseType of ApplicationInstance to get your hands on the Global.asax implementation.
Global.asax is always compiled into the same assembly as the assembly attributes from AssemblyInfo.cs, so this should work for all web applications that define a Global.asax.
For those that don't define their own Global.asax, it will fall back to the version of the generated global_asax type, which is always 0.0.0.0, and for applications that aren't web applications, it will just return no version at all.
Bonus; using the BuildManager class does not require an active HttpContext instance, which means you should be able to use this from application startup code as well.
public static Version GetHttpApplicationVersion() {
Type lBase = typeof(HttpApplication);
Type lType = BuildManager.GetGlobalAsaxType();
if (lBase.IsAssignableFrom(lType))
{
while (lType.BaseType != lBase) { lType = lType.BaseType; }
return lType.Assembly.GetName().Version;
}
else
{
return null;
}
}
HttpContext.Current.ApplicationInstance is derived from the class in the global.asax.cs. You can do the following
var instance = HttpContext.Current.ApplicationInstance;
Assembly asm = instance.GetType().BaseType.Assembly;
System.Version asmVersion = asm.GetName().Version;
It works both in ASP.NET (ASPX) and ASP.NET MVC
I encountered a similar problem, and thought you might find the solution useful.
I needed to report the current application version (of a web application project) from a custom server control, where the server control was contained in a different library. The problem was that the "easiest" assembly getters did not provide the right assembly.
Assembly.GetExecutingAssembly() returned the assembly containing the control; not the application assembly.
Assembly.GetCallingAssembly() returned different assemblies depending on where I was at in the call tree; usually System.Web, and sometimes the assembly containing the control.
Assembly.GetEntryAssembly() returned null.
new StackTrace().GetFrames()[idx].GetMethod().DeclaringType.Assembly retrieves the assembly of a frame in the stack trace at index idx; however, besides being inelegant, expensive, and prone to miscalculation on the frame index, it is possible for the stack trace to not contain any calls to the application assembly.
Assembly.GetAssembly(Page.GetType()) scored me the App_Web_##$##$%# assembly containing the dynamically generated page. Of course, the dynamic page inherits a class from my application assembly, so that led to the final solution:
Assembly.GetAssembly(Page.GetType().BaseType)
With the assembly reference in hand, you can drill to the version through its name:
var version = Assembly.GetAssembly(Page.GetType().BaseType)
.GetName()
.Version;
Now, this solution works because I had a reference to a type from the application assembly. We don't use any pages that do not inherit from a code behind, so it happens to be effective for us, but your mileage may vary if your organization's coding practices are different.
Happy coding!
Version version = new Version(Application.ProductVersion);
string message = version.ToString();
Some info here: http://www.velocityreviews.com/forums/showpost.php?p=487050&postcount=8
in asp.net 2.0 each page is built into it own assembly, so only the dll
the AssemblyInfo.cs is built into will
return the correct answer. just add a
static method to AssemblyInfo.cs that
returns the version info, and call
this method from your other pages.
-- bruce (sqlwork.com)
But I wrote a simple method to do that:
public static string GetSystemVersion(HttpServerUtility server)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(server.MapPath("~/web.config"));
System.Xml.XmlNamespaceManager ns = new System.Xml.XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("bla", "http://schemas.microsoft.com/.NetConfiguration/v2.0");
System.Xml.XmlNode node = doc.SelectSingleNode("/bla:configuration/bla:system.web/bla:authentication/bla:forms[#name]", ns);
string projectName = "";
if (node != null && node.Attributes != null && node.Attributes.GetNamedItem("name") != null)
projectName = node.Attributes.GetNamedItem("name").Value; //in my case, that value is identical to the project name (projetname.dll)
else
return "";
Assembly assembly = Assembly.Load(projectName);
return assembly.GetName().Version.ToString();
}
If you are looking for this from a web control, one hack is to find the type of the code-behind Page (ie. the class that inherits from System.Web.UI.Page). This is normally in the consumer's web assembly.
Type current, last;
current = Page.GetType();
do
{
last = current;
current = current.BaseType;
} while (current != null && current != typeof(System.Web.UI.Page));
return last;
I hope there is a better way.
The question states with no reference (instances) it did not (originally) say with no knowledge of web application types.
EDIT the OP clarified to state that yes they do really require no knowledge of types within the calling web assembly, so the answer is appropriate. However I would seriously consider refactoring such a solution such that the version is passed into the other assembly.
For most people in this scenario if you know the custom HttpApplication type:
typeof(MyHttpApplication).Assembly.GetName().Version
and if you only have a dynamic generated type:
typeof(DynamiclyGeneratedTypeFromWebApp).BaseType.Assembly.GetName().Version
Stop voting me down for this answer :)
So, I had to get the Assembly from a referenced dll.
In the asp.NET MVC/WebAPI world, there is always going to be at least one class which inherits from System.Web.HttpWebApplication. The implementation below searches for that class.
using System;
using System.Linq;
static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
The above uses System.Linq in order to find that relationship, but this can also be implemented without.
First, we get all loaded assemblies
AppDomain.CurrentDomain.GetAssemblies()
Then, enumerate through the IEnumerable<Assembly>, and get all of the types directly located in the assembly.
a.GetExportedTypes()
Then, see if any of the types inherit from System.Web.HttpWebApplication
t.BaseType?.FullName == "System.Web.HttpApplication"
In my implementation, I ensured this code would only be called once, but if that is not guaranteed, I'd highly wrapping this in a Lazy<T> or other cached lazy load implementation as it is rather expensive to keep performing the blind search.
using System;
using System.Linq;
// original method
private static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
// lazy load implementation
private static Lazy<Assembly> _webAssembly = new Lazy<Assembly>(GetWebAssembly);
public static Assembly WebAssembly { get => _webAssembly.Value; }

Categories

Resources