I have a .exe file as an embedded resource named IDMan.exe in my c# project. I want it to be copied in D:\ directory. i have the following code
public static void extractResource(String embeddedFileName, String destinationPath)
{
Assembly currentAssembly = Assembly.GetExecutingAssembly();
string[] arrResources = currentAssembly.GetManifestResourceNames();
foreach (string resourceName in arrResources)
if (resourceName.ToUpper().EndsWith(embeddedFileName.ToUpper()))
{
Stream resourceToSave = currentAssembly.GetManifestResourceStream(resourceName);
var output = File.OpenWrite(destinationPath);
resourceToSave.CopyTo(output);
resourceToSave.Close();
}
}
But whatever directory I choose it says
Access to path 'D:\' is Denied.
Related
I have a dll file as a resource in my project. Now I would like to access the directory folder in the dll.
E.g. Image dll (In Image.dll -> \Image\PresetFolder)
I would like to Directory.Getdirectories() folder path in the Image.dll
How could I can achieve this in c#???
At last, my friend provide me the answer, you have to load the dll first before get the directory path with code
private string[] GetAllResourcePath()
{
Assembly assembly = Assembly.Load("ImageDLL");
string resName = "ImageDLL.g.resources";
using (var stream = assembly.GetManifestResourceStream(resName))
{
using(var reader = new ResourceReader(stream))
{
return reader.Cast<DictionaryEntry>().Select(x => (string)x.Key).ToArray();
}
}
}
From this func, it will return all the resource directory path, and you can just filter out by using .Where() linq to get the directory you want.
I am trying to code a command line interface, the beginning has a scan for DLLs in a relevant folder (/dlls) but keeps throwing this error: Could not find a part of the path '/Users/danielshroff/Projects/Meh-Rewrite/Meh-Rewrite/bin/Debug/dlls)'. The path exists and I have copied and followed it exactly using finder goto folder
edit: i also tried using the full path but no luck
using System.IO;
namespace MehRewrite
{
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("MEH System Version 1.0");
Console.WriteLine("Loading Core System");
Console.WriteLine("Declaring Startup Variables");
String dlls = null;
Console.WriteLine("Startup Variables Declared");
Console.WriteLine("Searching for dlls");
foreach (var file in Directory.GetFiles(#"./dlls)", "*.dll"))
{
dlls = dlls + file;
Console.WriteLine(file); }
int present = dlls.IndexOf("tinyMath.dll", StringComparison.Ordinal);
Console.Write("Enter Secure Mode? ");
variables.secure = Console.ReadLine();
The problem is you have a ')' at the end of the path string you are passing to Directory.GetFiles.
The line should be:
foreach (var file in Directory.GetFiles(#"./dlls", "*.dll"))
In a MVC controller I use AssemblyLoadContext.Default.LoadFromAssemblyPath(pathToDll); to load an assembly. I want to delete or replace the given .dll file during runtime. This is not possible because the file is not disposed. Is there any way to dispose the .dll file? There are solutions using the AppDomain class, which is not available in asp.net core.
Background:
The user is able to upload a custom .dll file which contains implementations of a given interface. The user should also be able to replace his file. I use the following code in a controller to access the implementations:
var conventions = new ConventionBuilder();
conventions
.ForTypesDerivedFrom<IPluginContract>()
.Export<IPluginContract>()
.Shared();
var configuration = new ContainerConfiguration().WithAssembliesInPath(path, conventions);
using (var container = configuration.CreateContainer())
{
var plugins = container.GetExports<IPluginContract>();
return plugins;
}
With
public static ContainerConfiguration WithAssembliesInPath(
this ContainerConfiguration configuration,
string path, AttributedModelProvider conventions,
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
var fileNames = Directory
.GetFiles(path, "*.dll", searchOption);
List<Assembly> assemblies = new List<Assembly>();
foreach (string relativePath in fileNames)
{
Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath(relativePath));
assemblies.Add(assembly);
}
configuration = configuration.WithAssemblies(assemblies, conventions);
return configuration;
}
OPTION 1:
Try loading dll with method LoadFromStream, then you can remove dll without exceptions.
Ex:
foreach (string relativePath in fileNames)
{
using (var fs = File.Open(relativePath , FileMode.Open))
{
Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(fs);
assemblies.Add(assembly);
}
File.Delete(relativePath); //It doesn't throw exception
}
NOTE: tested with Net Core 3.1 but could work with previous versions.
OPTION 2:
If you have a problem when try to reload assemblies with LoadFromStream you should try to call AssemblyLoadContext.Default.Unload() before to LoadFromStream()
But I'm not sure if it works with AssemblyLoadContext.Default, so if you still keep any exception you should create any class that inherit from AssemblyLoadContext with flag isCollectible to true like this:
public class PluginLoadContext : AssemblyLoadContext
{
public PluginLoadContext() : base(isCollectible: true)
{
}
}
And the code should be:
//var pluginContext = new PluginLoadContext(); //In some place to call unload later
pluginContext.Unload();
foreach (string relativePath in fileNames)
{
using (var fs = File.Open(relativePath , FileMode.Open))
{
Assembly assembly = pluginContext.LoadFromStream(fs);
assemblies.Add(assembly);
}
File.Delete(relativePath); //It doesn't throw exception
}
OPTION 3:
There is another option that override Load method of your custom PluginLoadContext, you only need to load your entry dll, and the reference dll is knew with deps.json file of your entry dll.
In this example is using MemoryStream to prevent attach plugin dll.
public class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath) : base(isCollectible: true)//isCollectible doesn't appear in netstandard2.1
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null)
{
//Using MemoryStream to prevent attach dll to this .exe
MemoryStream ms = new MemoryStream();
using (var fs = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
fs.CopyTo(ms);
}
ms.Position = 0;
return LoadFromStream(ms);
}
return null;
}
}
Then you can load your entry plugin dll like this.
var dllPath = "<path to your entry dll>" // dll and deps.json file together .
var pc = new PluginLoadContext(dllPath);
var assembly = pc.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(dllPath)));
//You can load a reference dll too if you need it
var referenceAssembly = pc.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension("<path of reference dll>")));
REF:
https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support#load-plugins
When you load a dll into your application domain, this dll is not free before the appDomain is being destroyed (i.e. your process is stopped) there is no dispose for a dll.
For references on how to reach your desired functionality please have a look at these questions that are answered already:
Using AppDomain to dynamically load and unload dll
Hot unload and reload of a dll used by an application
It sounds very similar to MEF ( Managed Extensibility Framework ). It allows inject DLL's and also helps to manage the lifecycle.
Example:
public static class MefInjection
{
private static CompositionContainer mycontainer;
public static CompositionContainer MyContainer
{
get
{
if (mycontainer == null)
{
var catalog =
new DirectoryCatalog(".", "MyMEFProject.*");
mycontainer = new CompositionContainer(catalog);
}
return mycontainer;
}
}
}
The preceding code will grab all the exported values from all the assemblies in the same directory starting with "MyMEFProject". Then you can use mycontainer to get loaded DLL's functionality.
My directory structure looks like this:
-- Host Program Base
|- HostProgram.exe
|- SharedLIB.dll
|-- LoadedLibs
|- HostedLib.dll
HostProgram.exe is attempting to load HostedLib.dll, which depends on SharedLib.dll.
Thus, SharedLib.dll's ApplicationBase for the AppDomain I am creating to load it is /Host Program Base/HostedLibs/, but it needs to be able to find SharedLib.dll.
I have tried to add .. to the PrivateBinPath for the AppDomain but according to MSDN,
Private assemblies are deployed in the same directory structure as the application. If the directories specified for PrivateBinPath are not under ApplicationBase, they are ignored.
As the PrivateBinPath is not inside the ApplicationBase, but rather is one directory up, it is not inside ApplicationBase and is being ignored. Therefore I get a AssemblyResolveException when attempting to load the DLL into the new AppDomain.
I have also attempted to set the ApplicationBase to the Host Program Base folder and add HostedLibs as a PrivateBinPath, but this causes the domain to be unable to resolve HostedLib.dll at all.
So -> how do I resolve libraries outside ApplicationBase using an AppDomainSetup?
Short of reorganizing your application structure, you could use the AppDomain.AssemblyResolve event.
Basically works like this.
Subscribe to the AssemblyResolve event on the AppDomain.
When the event fires, you can specifically look for your SharedLib.dll or simply attempt to create a full path to the desired assembly in your root folder given the assembly name specified in the ResolveEventArgs.Name and use Assembly.LoadFrom(path).
If the assembly successfully loaded from the path, return it in the AssemblyResolve handler, otherwise return null.
Implemented solution based on Jim's answer:
internal static class Program
{
static Program()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
}
private static void Main()
{
//Do your stuff
}
private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
AssemblyName name = new AssemblyName(args.Name);
string expectedFileName = name.Name + ".dll";
string rootDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
return LoadAssembly(rootDir, expectedFileName, "", "Dlls", "../Dlls");
}
catch
{
return null;
}
}
private static Assembly LoadAssembly(string rootDir, string fileName, params string[] directories)
{
foreach (string directory in directories)
{
string path = Path.Combine(rootDir, directory, fileName);
if (File.Exists(path))
return Assembly.LoadFrom(path);
}
return null;
}
}
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);