I have several files that I have as embedded resources of a WPF application. I would like to be able to find the file versions of these resources without writing them out to a file first. Is this possible?
I'm not sure if this will help, but after searching for how to package my embedded resource .DLLs into one .exe, I ran into the code from below. You can use Assembly to gather an embedded resources, such as a .DLL's File Version. In short, using Assembly.Load(byte[]), you can figure out the file version.
var assemblies = new Dictionary<string, Assembly>();
var executingAssembly = Assembly.GetExecutingAssembly();
var resources = executingAssembly.GetManifestResourceNames().Where(n => n.EndsWith(".dll"));
foreach (string resource in resources)
{
using (var stream = executingAssembly.GetManifestResourceStream(resource))
{
if (stream == null)
continue;
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
try
{
//After Assembly.Load is called, you can find the File Version
assemblies.Add(resource, Assembly.Load(bytes));
}
catch (Exception ex)
{
System.Diagnostics.Debug.Print(string.Format("Failed to load: {0}, Exception: {1}", resource, ex.Message));
}
}
}
Some source can be found here.
This might help too.
Related
I am uploading a file to Api and trying to read the resource key and values. I am getting below exception when I try to read the file.
System.ArgumentException: Stream is not a valid resource file.
at System.Resources.ResourceReader._ReadResources()
at System.Resources.ResourceReader.ReadResources()
at System.Resources.ResourceReader..ctor(String fileName)
Below is the code which I tried.
[HttpPost]
public async Task<ActionResult> Post(IFormFileCollection files)
{
try
{
files = this.Request.Form.Files;
var tempFolder = Path.GetTempPath();
foreach (var formFile in files)
{
string fileName = ContentDispositionHeaderValue.Parse(formFile.ContentDisposition).FileName.Trim('"');
string filePath = Path.Combine(tempFolder, fileName);
if (formFile.Length > 0)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await formFile.CopyToAsync(stream).ConfigureAwait(false);
}
var resReader = new ResourceReader(#filePath); // Throwing an exception.
}
}
}
catch (Exception ex)
{
throw;
}
return this.Ok("Success.");
}
Below is the request Uri and file.
Am I missing any configuration?
ResourceReader reads binary resource files (.resources) not text resource flies (.resx). At compile time the text resource files are compiled to their binary equivalent.
Refer to this link https://learn.microsoft.com/en-us/dotnet/core/extensions/work-with-resx-files-programmatically; on how to work with .resx files programmatically.
If you have the file physically and the definition of the resource in your .resx file, just rebuild your solution and the problem will be solved.
Looks like in the .NET 4.8 Framework the ResourceReader reads .resource files and the ResXResourceReader reads .resx files now.
This was different in previous versions of .Net where you could just use the ResourceReader.
To use the ResxResourceReader, add a reference to System.Windows.Forms to your project, and change the code to use the ResXResourceReader instead of the ResourceReader.
Source: https://learn.microsoft.com/en-us/dotnet/api/system.resources.resxresourcereader?view=netframework-4.8
So the question is pretty simple. I'm using Xamarin.Android and I have a zip file in the Assets folder named "MyZipFile.zip", which I want extracted to the following path: System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
It sounds simple enough, but I cannot figure out how to read the Asset into memory through the AssetManager and then unzip it at the targeted location.
Is there a simple way to do this?
The Android Java framework includes a Java.Util.Zip package, so without adding any additional app libraries, I directly use it instead of using C# framework code, thus no bloat that linking can not remove.
So basically you are creating an asset stream and feeding that to a ZipInputStream and iterating over each ZipEntry in that zip stream to either create directories or files to your destination path.
UnZipAssets
public void UnZipAssets(string assetName, string destPath)
{
byte[] buffer = new byte[1024];
int byteCount;
var destPathDir = new Java.IO.File(destPath);
destPathDir.Mkdirs();
using (var assetStream = Assets.Open(assetName, Android.Content.Res.Access.Streaming))
using (var zipStream = new ZipInputStream(assetStream))
{
ZipEntry zipEntry;
while ((zipEntry = zipStream.NextEntry) != null)
{
if (zipEntry.IsDirectory)
{
var zipDir = new Java.IO.File(Path.Combine(destPath, zipEntry.Name));
zipDir.Mkdirs();
continue;
}
// Note: This is deleting existing entries(!!!) for debug purposes only...
#if DEBUG
if (File.Exists(Path.Combine(destPath, zipEntry.Name)))
File.Delete(Path.Combine(destPath, zipEntry.Name));
#endif
using (var fileStream = new FileStream(Path.Combine(destPath, zipEntry.Name), FileMode.CreateNew))
{
while ((byteCount = zipStream.Read(buffer)) != -1)
{
fileStream.Write(buffer, 0, byteCount);
}
}
Log.Debug("UnZipAssets", zipEntry.Name);
zipEntry.Dispose();
}
}
}
Usage:
UnZipAssets("gameModLevels.zip", Path.Combine(Application.Context.CacheDir.AbsolutePath, "assets"));
Note: Even through the asset/zip steam is fast, depending upon number/size of the zip entries and the speed of the flash the entry is being written to, this should be done on a background thread as not to block UI thread and cause an ANR
I have a simple WinForms application, but it has some Embedded Resources (in a subfolder under "Resources") that I would like to copy out to a folder on the computer. Currently, I have the latter working (with a explicit method naming the Embedded Resource and where it should go):
string path = #"C:\Users\derek.antrican\";
using (Stream input = Assembly.GetExecutingAssembly().GetManifestResourceStream("WINFORMSAPP.Resources.SUBFOLDER.FILE.txt"))
using (Stream output = File.Create(path + "FILE.txt"))
{
input.CopyTo(output);
}
But I'm still trying to figure out how to get the former working: looping through all the resources in the "WINFORMSAPP.Resources.SUBFOLDER" folder and moving them. I've done quite a bit of Googling, but I'm still not sure how to get a list of each Embedded Resource in this subfolder.
Any help would be GREATLY appreciated!
Start by getting all resources embedded in your assembly:
Assembly.GetExecutingAssembly().GetManifestResourceNames()
You can check these names against the name of your desired subfolder to see if they are inside or outside it with a simple call to StartsWith.
Now loop through the names, and get the corresponding resource stream:
const string subfolder = "WINFORMSAPP.Resources.SUBFOLDER.";
var assembly = Assembly.GetExecutingAssembly();
foreach (var name in assembly.GetManifestResourceNames()) {
// Skip names outside of your desired subfolder
if (!name.StartsWith(subfolder)) {
continue;
}
using (Stream input = assembly.GetManifestResourceStream(name))
using (Stream output = File.Create(path + name.Substring(subfolder.Length))) {
input.CopyTo(output);
}
}
I am rather new to c# and .NET, and trying to create an asp.net web application that dynamically loads assembly.
Initially, I've used Activator.CreateInstance to dynamically load assemblies, but it seems to lock the assembly DLL file. Because I am making frequent changes to the assembly it's become quite a pain. I also need to share the assembly with other apps, so it may become a problem later.
It appears that most people recommend creating a separate AppDomain and loading the assembly into it, then unload the appdomain after I'm done. However, my app and the assembly also depends on session context and all the session is lost once I send it over to the app domain; the assembly crashes because it cannot find session context.
Is there any way to pass on my session context to the AppDomain? Or is there any way for me to load the assembly without locking the DLL file? I've tried streaming the file as some suggested, but it still locks the DLL.
Edit: I've tried the following code as Davide Piras suggested, but the DLL file is still locked
private static T CreateInstance<T>(string fileName, string typeName)
{
if (!File.Exists(fileName)) throw new FileNotFoundException(string.Format("Cannot find assembly '{0}'.", fileName));
try
{
Assembly assembly = Assembly.LoadFrom(fileName);
if (assembly != null)
{
List<Type> assemblyTypes = assembly.GetTypes().ToList();
Type assemblyType =
assemblyTypes.FirstOrDefault(asmType => typeof(T).IsAssignableFrom(asmType));
T instance = (T) Activator.CreateInstance(assemblyType);
if (instance != null) return instance;
}
// Trouble if the above doesn't work!
throw new NullReferenceException(string.Format("Could not create type '{0}'.", typeName));
}
catch (Exception exp1)
{
throw new Exception("Cannot create instance from " + fileName + ", with type " + typeName + ": " + exp1.Message + exp1.Source, exp1.InnerException);
}
}
to load the assemblies in the same AppDomain but not lock the files after load just use the LoadFrom method in this way:
Assembly asm = Assembly.LoadFrom( “mydll.dll” );
in this way you are done and Session will be available.
there will be an issue with the debugger because symbols (*.pdb) will not get loaded so no breakpoint and no debugging available, to be able to debug you should really load the .pdb files in memory as well, for example using FileStream.
Edit: The way you can do to also load symbols and not lock the files is to use proper overload of Assembly.Load, the one that gets two byte[] one for the assembly and the other for the assembly' symbols file (.pdb file):
public static Assembly Load(
byte[] rawAssembly,
byte[] rawSymbolStore
)
in fact you should first load the bytes with a stream then call Assembly.Load and pass the byte[]
EDIT 2:
here a full example to load the assemblies in your current domain, including the symbol file and not having the files locks.
it's a full example found online, it reflect everything you need including the handling of AppDomain.AssemblyResolve...
public static void Main() {
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolver);
}
static void InstantiateMyType(AppDomain domain) {
try {
// You must supply a valid fully qualified assembly name here.
domain.CreateInstance("Assembly text name, Version, Culture, PublicKeyToken", "MyType");
} catch (Exception e) {
Console.WriteLine(e.Message);
}
}
// Loads the content of a file to a byte array.
static byte[] loadFile(string filename) {
FileStream fs = new FileStream(filename, FileMode.Open);
byte[] buffer = new byte[(int) fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
return buffer;
}
static Assembly MyResolver(object sender, ResolveEventArgs args) {
AppDomain domain = (AppDomain) sender;
// Once the files are generated, this call is
// actually no longer necessary.
EmitAssembly(domain);
byte[] rawAssembly = loadFile("temp.dll");
byte[] rawSymbolStore = loadFile("temp.pdb");
Assembly assembly = domain.Load(rawAssembly, rawSymbolStore);
return assembly;
}
I've got a situation where I have a DLL I'm creating that uses another third party DLL, but I would prefer to be able to build the third party DLL into my DLL instead of having to keep them both together if possible.
This with is C# and .NET 3.5.
The way I would like to do this is by storing the third party DLL as an embedded resource which I then place in the appropriate place during execution of the first DLL.
The way I originally planned to do this is by writing code to put the third party DLL in the location specified by System.Reflection.Assembly.GetExecutingAssembly().Location.ToString()
minus the last /nameOfMyAssembly.dll. I can successfully save the third party .DLL in this location (which ends up being
C:\Documents and Settings\myUserName\Local Settings\Application
Data\assembly\dl3\KXPPAX6Y.ZCY\A1MZ1499.1TR\e0115d44\91bb86eb_fe18c901
), but when I get to the part of my code requiring this DLL, it can't find it.
Does anybody have any idea as to what I need to be doing differently?
Once you've embedded the third-party assembly as a resource, add code to subscribe to the AppDomain.AssemblyResolve event of the current domain during application start-up. This event fires whenever the Fusion sub-system of the CLR fails to locate an assembly according to the probing (policies) in effect. In the event handler for AppDomain.AssemblyResolve, load the resource using Assembly.GetManifestResourceStream and feed its content as a byte array into the corresponding Assembly.Load overload. Below is how one such implementation could look like in C#:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var resName = args.Name + ".dll";
var thisAssembly = Assembly.GetExecutingAssembly();
using (var input = thisAssembly.GetManifestResourceStream(resName))
{
return input != null
? Assembly.Load(StreamToBytes(input))
: null;
}
};
where StreamToBytes could be defined as:
static byte[] StreamToBytes(Stream input)
{
var capacity = input.CanSeek ? (int) input.Length : 0;
using (var output = new MemoryStream(capacity))
{
int readLength;
var buffer = new byte[4096];
do
{
readLength = input.Read(buffer, 0, buffer.Length);
output.Write(buffer, 0, readLength);
}
while (readLength != 0);
return output.ToArray();
}
}
Finally, as a few have already mentioned, ILMerge may be another option to consider, albeit somewhat more involved.
In the end I did it almost exactly the way raboof suggested (and similar to what dgvid suggested), except with some minor changes and some omissions fixed. I chose this method because it was closest to what I was looking for in the first place and didn't require using any third party executables and such. It works great!
This is what my code ended up looking like:
EDIT: I decided to move this function to another assembly so I could reuse it in multiple files (I just pass in Assembly.GetExecutingAssembly()).
This is the updated version which allows you to pass in the assembly with the embedded dlls.
embeddedResourcePrefix is the string path to the embedded resource, it will usually be the name of the assembly followed by any folder structure containing the resource (e.g. "MyComapny.MyProduct.MyAssembly.Resources" if the dll is in a folder called Resources in the project). It also assumes that the dll has a .dll.resource extension.
public static void EnableDynamicLoadingForDlls(Assembly assemblyToLoadFrom, string embeddedResourcePrefix) {
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // had to add =>
try {
string resName = embeddedResourcePrefix + "." + args.Name.Split(',')[0] + ".dll.resource";
using (Stream input = assemblyToLoadFrom.GetManifestResourceStream(resName)) {
return input != null
? Assembly.Load(StreamToBytes(input))
: null;
}
} catch (Exception ex) {
_log.Error("Error dynamically loading dll: " + args.Name, ex);
return null;
}
}; // Had to add colon
}
private static byte[] StreamToBytes(Stream input) {
int capacity = input.CanSeek ? (int)input.Length : 0;
using (MemoryStream output = new MemoryStream(capacity)) {
int readLength;
byte[] buffer = new byte[4096];
do {
readLength = input.Read(buffer, 0, buffer.Length); // had to change to buffer.Length
output.Write(buffer, 0, readLength);
}
while (readLength != 0);
return output.ToArray();
}
}
There's a tool called IlMerge that can accomplish this: http://research.microsoft.com/~mbarnett/ILMerge.aspx
Then you can just make a build event similar to the following.
Set Path="C:\Program Files\Microsoft\ILMerge"
ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $(ProjectDir)\bin\Release\release.exe $(ProjectDir)\bin\Release\InteractLib.dll $(ProjectDir)\bin\Release\SpriteLib.dll $(ProjectDir)\bin\Release\LevelLibrary.dll
I've had success doing what you are describing, but because the third-party DLL is also a .NET assembly, I never write it out to disk, I just load it from memory.
I get the embedded resource assembly as a byte array like so:
Assembly resAssembly = Assembly.LoadFile(assemblyPathName);
byte[] assemblyData;
using (Stream stream = resAssembly.GetManifestResourceStream(resourceName))
{
assemblyData = ReadBytesFromStream(stream);
stream.Close();
}
Then I load the data with Assembly.Load().
Finally, I add a handler to AppDomain.CurrentDomain.AssemblyResolve to return my loaded assembly when the type loader looks it.
See the .NET Fusion Workshop for additional details.
You can achieve this remarkably easily using Netz, a .net NET Executables Compressor & Packer.
Instead of writing the assembly to disk you can try to do Assembly.Load(byte[] rawAssembly) where you create rawAssembly from the embedded resource.