How to load a signed assembly dynamically in c# - c#

Assembly myDll = Assembly.LoadFrom("D:\\ClassLib.dll, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=173d654960d26d29");
I am getting the exception saying "Could not load the assembly"
Please help me here.

Refer to the MSDN documentation for loading assembly. Try giving just the assembly path as an argument to this method and it would work as per the example in documentation.
In order to check the authenticity of your assembly what you can do is following:
string filePath = "C:/path/to/file.dll";
Assembly assembly = Assembly.LoadFrom(filePath);
Module module = assembly.GetModules().First();
X509Certificate certificate = module.GetSignerCertificate();
if (certificate == null)
{
// file is not signed.
}
As a matter of fact once your assembly is loaded you have most of the properties such as version number etc. in the assembly object.

Based on this article on MSDN website, there is a better way to check validity.
Paste this 2 line of code to the top of your relevant class.
[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);
Load your assembly
var filePath = "C:/whatever.dll";
var assembly = Assembly.LoadFrom(filePath);
Set the last 2 parameters regarding to your needs and call the function.
Little helper table
var alertMessage = "Spoofed!";
var isValid = StrongNameSignatureVerificationEx(filePath, ....);
if (!isValid)
throw new FileNotFoundException(alertMessage, filePath);
Note: As far as I know there is no managed version of this. So, be thread-safe when you use this function!

you can load the Assembly as follows
string path = #"D:\ClassLib.dll";
Assembly assembly = Assembly.LoadFrom(path);
More Sources here

Related

C# create instance of type from DLL extending host application type

Is this possible if not could some one please explain how i could implement this to work?
So i have a C# Application and a folder with it called modules, so files:
Application.exe
modules/
Application.Handler.ModuleName.dll
So inside the DLL it has the namespace Application.Handle containing the type ModuleName and ModuleName extends Handler that is implemented in Application.exe so to compile requires Application.exe as a reference.
Inside my host application i have:
string[] dirs = Directory.GetFiles(#"modules/", "Application.Handler.*.dll");
foreach(string filePath in dirs)
{
Assembly.LoadFile(new FileInfo(filePath).FullName);
string fileName = filePath.Split('/').Last();
string typeAssemblyName = fileName.Replace(".dll", "");
string typeName = typeAssemblyName.Split('.').Last();
}
But i'm unsure if i can implement the types from the strings i thought i could with Activator.CreateInstance but i'm not sure if I'm doing it correctly or if the way I'm trying to implement it works?
UPDATE
I might not have been clear but effectively what i need to do is
Application.Handler handler = new Application.Handler.ModuleName() Where Application.Handler.ModuleName in php it's done like below i thought there would be a system that returns an object of the type given in the string. if it's not there throw an exception
$className = "\Application\Handler\ModuleName";
$instance = new $className();
I have also tried using the Unwrap system that #rene suggested
Assembly asm = Assembly.LoadFile(new FileInfo(filePath).FullName);
string fileName = filePath.Split('/').Last();
string typeAssemblyName = fileName.Replace(".dll", "");
string typeName = typeAssemblyName.Split('.').Last();
FrameHandler fh;
fh = (FrameHandler)Activator.CreateInstance(asm.FullName, typeAssemblyName).Unwrap();
fh.RegisterHandlers();
using this method where i give it the Assembly name it gives me a FileNotFoundException and without the Assembly name i get TypeLoadException but it must be loading the manifest of the assembly as Application.Handler.ModuleName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
You just need a handle to the type, so you'll need the assembly path and the type's full name.
var assy = Assembly.LoadFile("...");
var type = assy.GetType("...");
var obj = Activator.CreateInstance(type);

Get Type from Fully qualified name only in Windows Store App

I have a string containing a full qualified name like MyNamespace.MyType which I know is in a loaded assembly.
I need to get the Type instance of this, in a windows store app.
The issue I'm having is that while there is some reflection classes in windows store apps, it's very limited, and I simply can't use what I've been using for a desktop app.
If I can get an assembly I can find my type within it so I'm currently trying to get all loaded assemblies, which I can't do easily as AppDomain doesn't exist.
I found the following:
private async System.Threading.Tasks.Task<IEnumerable<Assembly>> GetAssembliesCore()
{
var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
List<Assembly> assemblies = new List<Assembly>();
foreach (Windows.Storage.StorageFile file in
await folder.GetFilesAsync().AsTask().ConfigureAwait(false))
{
if (file.FileType == ".dll")
{
AssemblyName name = new AssemblyName() { Name = file.Name };
Assembly asm = Assembly.Load(name);
assemblies.Add(asm);
}
}
return assemblies;
}
I added the .AsTask().ConfigureAwait(false) to stop it hanging, but it now fails trying to load the assembly:
"Could not load file or assembly 'FDE.Audio.dll' or one of its dependencies.
The system cannot find the file specified.":"FDE.Audio.dll"
Is there something I need to set up in the manifest? Something else?
How can I load an assembly in my program's folder (AppX I think)?
Try to extract file name without extension
var filename = file.Name.Substring(0, file.Name.Length - file.FileType.Length);
AssemblyName name = new AssemblyName() { Name = filename };
Assembly asm = Assembly.Load(name);

How to load a DLL file to determine its dependent assembly names?

At run time I want to load an assembly and need to find the names of its dependent assemblies, so that I can determine which assemblies are required to execute the given DLL file.
You'll need to load the assembly (DLL file) into a Reflection-Only context.
After that you can use GetReferencedAssembles to find dependencies.
I used this some time ago in a nasty bit of code:
Where you load your assembly, register the resolve event:
AppDomain.CurrentDomain.AssemblyResolve += Assemblies_AssemblyResolve;
Assembly.LoadFile("<path to your assembly>");
AppDomain.CurrentDomain.AssemblyResolve -= Assemblies_AssemblyResolve;
The resolve event handler is called for every referenced dll. here i try to load the assembly.
Assembly Assemblies_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.RequestingAssembly != null)
{
return LoadAssemblyFromPath(new AssemblyName(args.Name), args.RequestingAssembly.Location);
}
if (assemblyTryPath != null)
{
return LoadAssemblyFromPath(new AssemblyName(args.Name), assemblyTryPath);
}
return null;
}
And a little helper where the actual loading happens:
private Assembly LoadAssemblyFromPath(AssemblyName assemblyName,string fullPath)
{
if (assemblyName == null||fullPath==null)
return null;
string path = Path.GetDirectoryName(fullPath);
string dllName = assemblyName.Name + ".dll";
string fullPath2Try = Path.Combine(path, dllName);
Assembly loadedAssembly = Assembly.LoadFrom(fullPath2Try);
return loadedAssembly;
}
Hope, that helps!
I found answer. If we want to find the Referenced assemblies of unloaded assembly, we can find from following way.
Assembly _Assembly = Assembly.ReflectionOnlyLoadFrom(#"H:\Account.dll");
AssemblyName[] _AN = _Assembly.GetReferencedAssemblies();

Issue with assembly createinstance and crystal report

I load an assembly
private System.Reflection.Assembly;
object myData;
myAssembly = System.Reflection.Assembly.LoadFile("C:\\CrystalDecisions.CrystalReports.Engine.dll");
then i create an instance.
myData=myAssembly.CreateInstance("CrystalDecisions.CrystalReports.Engine.ReportDocument", true);
this myData always returns null, any thought why it is returning null where as myAssembly has the assembly information and its public key token?
try something like the following below..
// dynamically load assembly from file Test.dll
Assembly myData = Assembly.LoadFile(#"C:\CrystalDecisions.CrystalReports.Engine.dll");
// get type of class Calculator from just loaded assembly
Type myData = myData.GetType("CrystalDecisions.CrystalReports")
// create instance of class Calculator
object myDataInstance = Activator.CreateInstance(myData);
Reflection Examples C#

AppDomain.CurrentDomain.AssemblyResolve asking for a <AppName>.resources assembly?

using the code How to embed a satellite assembly into the EXE file provided by csharptest.net, I've created a custom assembly resolver and embedded my assemblies in my resources.
I can successfully resolve my assemblies used in but somehow AppDomain.CurrentDomain.AssemblyResolve asks for an assembly called 'AppName.resources' specifically "MyProgram.resources, Version=0.15.3992.31638, Culture=en-US, PublicKeyToken=null" which i don't know how to resolve?
I've tried to disable loading my custom assemblies from resources (placed all my assembly dll's in program directory) and just enabled AppDomain.CurrentDomain.AssemblyResolve, but it was still asking for it.
I'm a bit confused about this, will appreciate a lot if you can help me on this.
Here's my code for interested ones;
static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string name = args.Name.Substring(0, args.Name.IndexOf(','));
if (name == "MyProgram.resources") return null;
else name = string.Format("MyProgram.Resources.Assemblies.{0}.dll", name);
lock (_loadedAssemblies)
{
if (!_loadedAssemblies.TryGetValue(name, out assembly))
{
using (Stream io = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
{
if (io == null)
{
MessageBox.Show("MyProgram can not load one of it's dependencies. Please re-install the program", string.Format("Missing Assembly: {0}", name), MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(-1);
}
using (BinaryReader binaryReader = new BinaryReader(io))
{
assembly = Assembly.Load(binaryReader.ReadBytes((int)io.Length));
_loadedAssemblies.Add(name, assembly);
}
}
}
}
return assembly;
}
Answering on my own;
Adding this line to AssemblyInfo.cs solves it and resolver will not get asked for resources any-more.
[assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.MainAssembly)]
Though this is a work-around should be carefully considered multi-language applications.
More Info:
https://connect.microsoft.com/VisualStudio/feedback/details/526836/wpf-appdomain-assemblyresolve-being-called-when-it-shouldnt
http://blogs.msdn.com/b/kimhamil/archive/2008/11/11/what-does-the-neutralresourceslanguageattribute-do.aspx
http://forums.devshed.com/net-development-87/c-wpf-appdomain-assemblyresolve-being-called-when-it-shouldn-t-669567.html
http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
This approach fails for machines with non en-US cultures. A better approach is ignoring resources on assembly resolver;
public Assembly Resolver(object sender, ResolveEventArgs args)
{
lock (this)
{
Assembly assembly;
AssemblyName askedAssembly = new AssemblyName(args.Name);
string[] fields = args.Name.Split(',');
string name = fields[0];
string culture = fields[2];
// failing to ignore queries for satellite resource assemblies or using [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)]
// in AssemblyInfo.cs will crash the program on non en-US based system cultures.
if (name.EndsWith(".resources") && !culture.EndsWith("neutral")) return null;
/* the actual assembly resolver */
...
}
}
My situation was a bit more complex and the above solution did not work for me. (That is changing the AssemblyInfo.cs file)
I have moved all my form and image resources to a seperate dll and the moment any of the images are used the 'filenotfoundexception' exception is thrown.
The important information is the following:
Beginning with the .NET Framework 4, the ResolveEventHandler event is raised for all assemblies, including resource assemblies. See the following reference
https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx
The solution turned out to be very simple. If a resource file is requested in the form 'dllname.resources.dll' always return null;
Here is the event code that I have adapted from other samples found. (I have commented the debugging lines - un-comment them if you have a problem using the code.
Add this line in your class. It is used to prevent loading a dll more than once
readonly static Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
This is the event method.
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string keyName = new AssemblyName(args.Name).Name;
if (keyName.Contains(".resources"))
{
return null; // This line is what fixed the problem
}
if (_libs.ContainsKey(keyName))
{
assembly = _libs[keyName]; // If DLL is loaded then don't load it again just return
return assembly;
}
string dllName = DllResourceName(keyName);
//string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); // Uncomment this line to debug the possible values for dllName
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(dllName))
{
if (stream == null)
{
Debug.Print("Error! Unable to find '" + dllName + "'");
// Uncomment the next lines to show message the moment an assembly is not found. (This will also stop for .Net assemblies
//MessageBox.Show("Error! Unable to find '" + dllName + "'! Application will terminate.");
//Environment.Exit(0);
return null;
}
byte[] buffer = new BinaryReader(stream).ReadBytes((int) stream.Length);
assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
private static string DllResourceName(string ddlName)
{
if (ddlName.Contains(".dll") == false) ddlName += ".dll";
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (name.EndsWith(ddlName)) return name;
}
return ddlName;
}

Categories