I have a modularized application where each module is it's own project. Each module can then be packaged into a single dll.
I have added my own custom configuration file for each module called "Scripts.config" within the root of the project. I was wondering if there was a way to get all the Scripts.config files in the application.
The following code is used to get all implementations of a particular type:
private IList<Type> GetTypes<T>() {
return BuildManager.GetReferencedAssemblies().Cast<Assembly>().SelectMany(a => a.GetExportedTypes().Where(t => typeof(T).IsAssignableFrom(t) && !t.IsAbstract)).ToList();
}
I guess i'm looking for the equivalent but to get all the "Script.config" files. I guess I could embed the Scripts.config file but I was wondering if there was a better solution.
Sorry if I haven't explained this clearly. I'd really appreciate any help. Thanks
As I thought embedding the resource was the best way to go. I simply get the required assemblies and then use the following code for each assembly to retrieve the content of the Scripts.config file.
using (var stream = assembly.GetManifestResourceStream(assembly.GetManifestResourceNames().Single(n => n.EndsWith("Scripts.config")))) {
using (var sr = new StreamReader(stream)) {
var content = sr.ReadToEnd();
...
}
}
Related
Sorry in advance I'm not sure if I've phrased the question correctly, here's my situation... Using .NET 4.6 with MEF.
I have a core website that, at run time, checks a modules folder for DLLs and pulls them into a Composition Container / MEF thing, which lets me use the views/controllers of the 3rd party project, in my core.
To allow strong typing, I followed this guide which suggests making a shadow copy of the DLLs in a PreApplicationStartMethod.
All working so far, really great.
The problem comes when I stop debugging or when the server recompiles. The DLLs are not being released properly, so I get access denied errors 2nd time around. The error happens when I try to copy DLLs into the shadow copy folder.
The process cannot access the file '....dll' because it is being used by another process.
I guess it's the BuildManager.AddReferencedAssembly(assemblyDll) which is locking the file in... but is there a reliable way to unload the assembly either on crash or on start up?
static PreApplicationInit()
{
PluginFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/Modules"));
ShadowCopyFolder = new DirectoryInfo(HostingEnvironment.MapPath("~/Modules/temp"));
}
public static void Initialize()
{
Directory.CreateDirectory(ShadowCopyFolder.FullName);
//clear out plugins)
foreach (var f in ShadowCopyFolder.GetFiles("*.dll", SearchOption.AllDirectories))
{
f.Delete(); // -- Breaks here
}
//shadow copy files
foreach (var plug in PluginFolder.GetFiles("*.dll", SearchOption.AllDirectories))
{
var di = Directory.CreateDirectory(Path.Combine(ShadowCopyFolder.FullName, plug.Directory.Name));
File.Copy(plug.FullName, Path.Combine(di.FullName, plug.Name), true); // -- Or if Delete is Try Caught, Breaks here
}
foreach (var a in
ShadowCopyFolder
.GetFiles("*.dll", SearchOption.AllDirectories)
.Select(x => AssemblyName.GetAssemblyName(x.FullName))
.Select(x => Assembly.Load(x.FullName)))
{
BuildManager.AddReferencedAssembly(a);
}
}
There can be many possible reasons but the main reason for this i think is, when you recompile some of the dll from your previous compile are still in process and it wont let you have access until the entire process is finished (which in a term it will have a lock).
if you want to recompile try changing the folder. it should work.
Now, I am working on edit existing string/icon resource assembly which is code in C# in VS. I have search some method to edit the binary file directly, particularly, I use mono.cecil (http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/), almost all the localized resource files work fine. But only the English original resource file does not work. So I think I should give up this way, I hope to edit the file manually, either open source or original .net API is ok. Anyone have this kind experience to edit the resource file, please let me know:
BTW, the English project contains core logic code and references other dlls (OtherDLL.dll), this may cause exceptions when using mono.cecil, the code and exception is below.
AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(resourceFileName);
// Some code
assemblyDefinition.Write(newFileName); // This will cause exception: "Failed to resolve assembly: 'OtherDLL, Version=10.1.1.1, Culture=neutral, PublicKeyToken=null'
The english dll is TestDll.dll under deployment directory, and other localized resource dlls are TestDll.resources.dll under localized directory, like /de/TestDll.resources.dll and /zh-CN/TestDll.resources.dll.
Now I need the method to achieve the target(edit and save resource part), so please help me to find a way to achieve the goal. Any comments will be appreciated.
Thanks in advance.
The problem is that you need to set the search directories for the assembly references in the metadata tables to be rewritten correctly:
var assemblyFile = #"c:\myassembly.dll";
var resolver = new DefaultAssemblyResolver();
// add directory of the source assembly for references
resolver.AddSearchDirectory(Path.GetDirectoryName(assemblyFile));
// add .NET runtime directories
var runtimeDir = RuntimeEnvironment.GetRuntimeDirectory();
foreach (var dir in Directory.GetDirectories(RuntimeEnvironment.GetRuntimeDirectory(), "*", SearchOption.AllDirectories))
{
resolver.AddSearchDirectory(dir);
}
var mod = AssemblyDefinition.ReadAssembly(assemblyFile, new ReaderParameters { AssemblyResolver = resolver }).MainModule;
mod.Write(assemblyFile + ".patched");
When you want to change resources with Mono.Cecil:
var strings = mod.Resources.SingleOrDefault(a => a.Name == "English.resources");
mod.Resources.Remove(strings);
using var ms = new MemoryStream();
using var rw = new ResourceWriter(ms);
rw.AddResource("GreetingText", "Hello World");
rw.Generate();
ms.Position = 0;
mod.Resources.Add(new EmbeddedResource("English.resources", ManifestResourceAttributes.Public, ms));
mod.Write(assemblyFile + ".patched");
Regards
In a DNX application, which uses a "project.json" file, is there a way to read the value of the "version" property out of the "project.json" file?
I'm writing a library that writes something to the current HTTP response and I would like to show the version of the application in there.
Any help on how this can be done is highly appreciated.
If you set the version attribute during build (or in any other way) you can do this like that:
using System;
using System.Reflection;
[assembly:AssemblyVersionAttribute("1.2.3")]
namespace Test
{
class Program
{
public static void Main()
{
var assembly = typeof(Program).GetTypeInfo().Assembly;
var name = assembly.GetName();
Console.WriteLine($"{name.Name}: {name.Version}");
}
}
}
I did it using the new dotnet cli which is replacing dnx but it should work with dnx dnxcore50 as well.
Are you writing a Class Library or an ASP.NET application?
If a class Library, you could copy the version string to a resource file that you read in during run-time to grab the version. It's kind hard to do this sort of thing with class libraries since you don't get the beauty of a Startup and IoC.
If ASP.NET, then just add a version into your appsettings.json configuration (or a custom json file to store settings) and read it in at startup: http://docs.asp.net/en/latest/fundamentals/configuration.html
Multipe ways of doing this if you are running in a the web application, not a class library.
First way custom attributes data (should check if attribute is available):
this.GetType().Assembly.GetCustomAttributesData()
.First(x => x.AttributeType.FullName == "System.Reflection.AssemblyInformationalVersionAttribute")
.ConstructorArguments[0];
Second way
var name = this.GetType().AssemblyQualifiedName;
name = name.Substring(name.IndexOf("Version=") + 8);
var verion = name.Substring(0, name.IndexOf(", "));
I am trying to create a Solution from a single source file and tested different solutions.
One of them is the following:
var info = ProjectInfo.Create(
projectId,
version: VersionStamp.Default,
name: "TestProject",
assemblyName: "TestProject.dll",
language: LanguageNames.CSharp);
using (var ws = new CustomWorkspace())
{
var project = ws.AddProject(info);
}
But when running this code, I just get an exception saying that "language is not supported".
Any hint about what is happening?
You need to make sure Microsoft.CodeAnalysis.Workspaces.CSharp.dll is copied alongside your project. We detect that it's there and load it to provide C# support.
I have a Visual Studio Solution with two projects inside.
The first project is a windows service, and this project contains one XML file inside a folder (called Configurations). This XML file is called Databases.xml. I have changed Databases.xml Build Action from content to embedded resource, and now I want to access this XML file from my other project in my solution, which is a WPF application.
I have therefore added an reference to my windows service project inside my WPF project, and would now like to access my XML file from my WPF project.
My problem is that when I am trying to access the embedded resource then I can't find out which type to use and what the path/namespace to my assembly and XML file should be. When I am using the
string[] names = this.GetType().Assembly.GetManifestResourceNames();
my names array is filled out with some resources from my WPF project. What I want is to access the ResourceNames and of course my Databases.xml file from my Windows Service project.
Please help me since this problem is driving me nuts.
If you need any additional information, please let me know.
My Solution Update 26-07-2013
I found out that the real problem occured when I couldn't use my first windows Service projects namespace as a type for my assembly. my Windows Service consists of a service class (with OnStart() and OnStop() method inside), and in order to use this class as my namespace type, I needed to add another reference to my WPF project. I needed to add a reference to System.ServiceProcess namespace, in order to use my Windows Service Class as a type for my assembly in my WPF Project.
In Order to access my Databases.xml file, I have come up with this solution. Remember to insert your own projects name and class name instead of my placeholders (<Windows Service Project Name> etc).
//Remember to add a reference to System.ServiceProcess in order to be able to use your WIndows Service Project as an assembly type.
using (Stream stream = typeof(<Windows Service Project Name>.<Windows Service Class Name>).Assembly.GetManifestResourceStream("<Windows Service Project Name>.<Folder Name>.Databases.xml"))
{
//Load XML File here, for instance with XmlDocument Class
XmlDocument doc = new XmlDocument();
doc.Load(stream);
}
So my real problem was that I didn't include the System.ServiceProcess reference to my second project.
You've to refer to Windows Service project Assembly to make it work
The problem with your code is This.GetType().Assesmbly gives current Assembly In your case WPF Assembly and obviously you'll not find what you need there.
Try this
Assembly windowsServiceAssembly = typeof(SomeTypeFromThatAssembly).Assembly;
string[] names = windowsServiceAssembly.GetManifestResourceNames();
Hope this helps.
If your class is static class then use this methods:
internal static string GetFromResources(string resourceName)
{
var asm = Assembly.GetExecutingAssembly();
var resource = asm.GetManifestResourceNames().First(res => res.EndsWith(resourceName, StringComparison.OrdinalIgnoreCase));
using (var stream = asm.GetManifestResourceStream(resource))
{
if (stream == null) return string.Empty;
using (var reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}
For example if your embedded resource file names on the this project is 'MyFile.txt' then use this static method same this code:
var myFileData = GetFromResources("MyFile.txt");