I'm using ASP.NET MVC3, StructureMap and SharpSvn.
Here's the code that I'm using:
public class SvnFileReader : ISvnFileReader
{
private readonly string _svnAddress;
public SvnFileReader(string svnAddress)
{
_svnAddress = svnAddress;
}
public void DownloadFiles(DirectoryInfo destination)
{
using (var svnClient = new SvnClient())
{
// checkout the code to the specified directory
svnClient.CheckOut(new Uri(_svnAddress), destination.FullName);
}
}
}
When I execute this code:
_svnFileReader.DownloadFiles(new System.IO.DirectoryInfo(#"d:\test"));
I get the following error message:
Could not load file or assembly
'file:///D:\Projects\SvnFileReaderDemo\bin\SharpSvn-DB44-20-Win32.dll'
or one of its dependencies. The module
was expected to contain an assembly
manifest.
Any help would be greatly appreciated!
You should exclude the SharpSvn DLLs from StructureMap automatic assembly scanning for dependencies. This is an unmanaged library but because you have configured StructureMap to look for types in all dlls when it tries to load this one it breaks.
UPDATE:
If you are running this code on a x64 bit OS you may try downloading the specific x64 SharpSvn which uses SharpSvn-DB44-20-x64.dll.
Related
== compile command ==
csc -r:"../Newtonsoft.Json.dll" test.cs
== exec command ==
mono test.exe
== exec result : dependency error ==
System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=11.0.0.0, Culture=neutral,
PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies.
"Newtonsoft.Json.dll" this file is located in parent path. so I added a reference about dll and compile succeeded, but when I executed the exe file, it failed to get dll reference I added.
And when I put cs file and dll file together in the same directory, it worked very well, but that's not what I wanted.
Is there a solution to add a reference from dll file which is located in parent path using command line interface?
I used csc for compiler and mono for execution.
Thanks.
References are pathless. What that means is that wherever the assembly resides, all your program knows is that it has a reference to Newtonsoft.Json, Version=x.x.x.x, Culture=... and so on. You can do some things with the application configuration (application.config or myprogram.exe.config) to organize things into subfolders (using the probing setting) or specify a URL location for the file (using the codebase setting). You can set up the environment to change the search path and so on.
Or you can add some runtime code that allows you to override the default behavior and the call Assembly.LoadFrom to provide a full path to the file. You can either do it as part of your initialization or in a handler for the AppDomain.AssemblyResolve event - which is generally better method since it will only be called when the assembly is actually needed.
For example:
using System.IO;
using System.Reflection;
static class ParentPathResolver
{
public static void Init()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolve);
}
private static Assembly? Resolve(object? sender, ResolveEventArgs args)
{
var filename = new AssemblyName(args.Name).Name + ".dll";
var fullname = Path.GetFullPath(Path.Combine("..", filename));
if (File.Exists(fullname))
return Assembly.LoadFrom(fullname);
return null;
}
}
Of course you can add your own code to the Resolve method to search pretty much anywhere, just as long as you don't get caught in a resolution loop. I've used the AssemblyResolve event to do fun things like loading assemblies from compressed resources.
Should it be possible to use ef-core-5.0 in a native c++ application using an c++/cli interop assembly with .net core 5 as the target framework? To experiment with this I've modified the netcore branch of the CppCliMigrationSample (https://github.com/mjrousos/CppCliMigrationSample), changing the from "netcoreapp3.1" to "net5.0" for CppCliInterop and the from "net47;netcoreapp3.1" to "net5.0-windows" for the ManagedLibrary. The sample builds and works as expected with these changes. However, adding the efcore 5 assemblies to ManagedLibrary and trying to a simple query on a scaffolded model fails with the following error:- System.IO.FileNotFoundException: 'Could not load file or assembly 'Microsoft.EntityFrameworkCore, Version=5.0.5.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. The system cannot find the file specified.'. I figure I need an entry in the app's .config but I'm not sure what it should be. Can anyone help with resolving this?
Following is what I have in my modified ManagedLibrary.csproj:-
ManagedLibrary.csproj
Sample query:
using ManagedLibrary.Context;
using ManagedLibrary.Model;
using System.Linq;
namespace ManagedLibrary
{
public static class Mi2cdbData
{
public static Prjdata GetFirstProject()
{
using (var context = new BaseContext())
{
return context.Prjdata.FirstOrDefault();
}
}
}
}
The following shows how it's being called in CppClinterop.cpp:-
CppClinterop.cpp
I'm trying to connect to a hyperSQL database (HSQLDB) on my local machine from a c# application in visual studio.
I've ran through the steps to create the .net JDBC driver to build the dll, and also downloading the demo console application in the "download" section from the following url: http://nikolaiklimov.de/query-java-HyperSQL-database-with-csharp/
The demo application works!! i can connect to the database and query its contents . Next I have converted the console app into a class library then call the class library to query the DB but this is where it falls over and I get initialization errors of System.TypeInitializationException. any idea why the project falls over after converting to a class library. (if i convert the class library straight back a console app it works again).
The code and connection string are:
namespace HyperSQL
{
public static class sqlconnector
{
readonly static string CONNECTION_STRING =
ConfigurationManager.ConnectionStrings["HyperSQL"].ConnectionString;
const string SQL = "SELECT * FROM meeting";
public static void getdata()
{
try
{
java.sql.DriverManager.registerDriver(new org.hsqldb.jdbcDriver());
using (java.sql.Connection conn = java.sql.DriverManager.getConnection(CONNECTION_STRING))
{
java.sql.PreparedStatement ps = conn.prepareStatement(SQL);
using (java.sql.ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
Console.WriteLine($"MEETING_NO={rs.getInt("MEETING_NO")}");
Console.WriteLine("------------------");
}
}
}
}
catch (Exception ex)
{
}
Console.ReadLine();
}
}
}
jdbc:hsqldb:hsql://localhost:3458/elitedb;crypt_key=DADADADADAADDADAD;crypt_type=AES;shutdown=true;write_delay=false;user=****;password=****
Ive added a console app to my solution after the conversion to a class libary. The console app code is below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
try
{
HyperSQL.sqlconnector.getdata();
}
catch (Exception ex)
{
}
}
}
}
Here is a link to download my solution created in visual studio. It contains a console application that calls a function in a class library. The class library (HyperSQL) itself is simply converted from a console application and can be converted back. You will need a running instance of HyperSQL on your machine to be able to connect successfully.
http://eliteservicedev.azurewebsites.net/DemoHyperSQL.zip
Have you seen the error listed in the original site you posted?
If your forget to add runtime dependencies to the build folder of your
project then you can get these errors: Could not load file or
assembly 'IKVM.OpenJDK.Util, Version=8.1.5717.0, Culture=neutral,
PublicKeyToken=13235d27fcbfff58' or one of its dependencies. The
system cannot find the file specified. TypeInitializationException:
The type initializer for 'org.hsqldb.jdbc.JDBCDriver' threw an
exception: FileNotFoundException: Could not load file or assembly
'IKVM.Runtime, Version=8.1.5717.0, Culture=neutral,
PublicKeyToken=13235d27fcbfff58' or one of its dependencies. 'The
type initializer for 'sun.util.locale.provider.LocaleProviderAdapter'
threw an exception.' FileNotFoundException: Could not load file or
assembly 'IKVM.OpenJDK.Text, Version=8.1.5717.0, Culture=neutral,
PublicKeyToken=13235d27fcbfff58' or one of its dependencies. 'The
type initializer for 'org.hsqldb.HsqlDateTime' threw an exception.'
InvalidCastException: Unable to cast object of type
'java.util.PropertyResourceBundle' to type
'sun.util.resources.OpenListResourceBundle'.
***** UPDATE
With the source project i see an error, looking in the bin\debug folder i see that non all the referenced file are copied to ConsoleApp1.exe bin folder: this is the compare result:
Confronto in corso dei file consoleapp1.txt e DEMOCSHARPTHYPERSQL.TXT
***** consoleapp1.txt
ConsoleApp1.exe
ConsoleApp1.exe.config
ConsoleApp1.pdb
hsqldb.dll
HyperSQL.dll
***** DEMOCSHARPTHYPERSQL.TXT
hsqldb.dll
HyperSQL.dll
*****
***** consoleapp1.txt
IKVM.OpenJDK.Jdbc.dll
IKVM.OpenJDK.Text.dll
***** DEMOCSHARPTHYPERSQL.TXT
IKVM.OpenJDK.Jdbc.dll
IKVM.OpenJDK.Localedata.dll --> Missing in ConsoleApp1.exe folder
IKVM.OpenJDK.Text.dll
*****
If i manually copy the missing dll on ConsoleApp1.exe folder the program run correctly. I think that is a visual studio bug
Seems VS is not copying all IKVM DLLs to output folder due to not resolving they are needed. Please see this SourceForge issue and this GitHub issue, the later one with my comments.
I'm working on a plugin for a existing C# .NET Program. It's structured in a manner where you put your custom .dll file in Program Root/Plugins/your plugin name/your plugin name.dll
This is all working well, but now I'm trying to use NAudio in my project.
I've downloaded NAudio via Nuget, and that part works fine, but the problem is that it looks for the NAudio.dll in Program Root, and not in the folder of my plugin.
This makes it hard to distribute my plugin, because it would rely on users dropping the NAudio.dll in their Program Root in addition to putting the plugin into the "Plugins" folder.
Source:
SettingsView.xaml:
<Button HorizontalAlignment="Center"
Margin="0 5"
Width="120"
Command="{Binding SoundTestCommand,
Source={StaticResource SettingsViewModel}}"
Content="Sound Test" />
SettingsViewModel.cs:
using NAudio.Wave;
.
.
.
public void SoundTest()
{
IWavePlayer waveOutDevice;
WaveStream mainOutputStream;
WaveChannel32 inputStream;
waveOutDevice = new WaveOut();
mainOutputStream = new Mp3FileReader(#"E:\1.mp3");
inputStream = new WaveChannel32(mainOutputStream);
inputStream.Volume = 0.2F;
waveOutDevice.Init(mainOutputStream);
waveOutDevice.Play();
}
How can I get C# to look for NAudio in Program Root/Plugins/my plugin name/NAudio.dll instead of looking for it in Program Root/NAudio.dll ?
I'm using VS Express 2013, Target Framework is 4.5 and Output type is Class Library.
Edit:
I found 2 ways to make this work ( I'm not sure what the pros and cons of both methods are - if anyone knows I would appreciate additional information ).
Using the NuGet Package Costura.Fody.
After installing the NuGet package, I simply had to set all other References "Copy Local" to "False" and then set "Copy Local" for NAudio to "True".
Now when I build, the NAudio.dll is compressed and added to my own DLL.
Using the AssemblyResolver outlined below.
It didn't work right away though, so here is some additional information that may help anyone facing the same issue:
I put Corey's code as he posted it into the Helpers folder.
My entry point is Plugin.cs, the class is public class Plugin : IPlugin, INotifyPropertyChanged
In there, the entry method is public void Initialize(IPluginHost pluginHost), but simply putting PluginResolver.Init(path) did not work.
The host program uses WPF and is threaded and I had to use a dispatcher helper function of the host program to get it to work: DispatcherHelper.Invoke(() => Resolver.Init(path));
As mentioned, I'm currently unsure which method to use, but I'm glad I got it to work. Thanks Corey!
You can use the PATH environment variable to add additional folders to the search path. This works for native DLLs, but I haven't tried to use it for .NET assemblies.
Another option is to add a hook to the AssemblyResolve event on the current application domain and use a custom resolver to load the appropriate assembly from wherever you find it. This can be done at the assembly level - I use it in NAudio.Lame to load an assembly from a resource.
Something along these lines:
public static class PluginResolver
{
private static bool hooked = false;
public static string PluginBasePath { get; private set; }
public static void Init(string BasePath)
{
PluginBasePath = BasePath;
if (!hooked)
{
AppDomain.CurrentDomain.AssemblyResolve += ResolvePluginAssembly;
hooked = true;
}
}
static Assembly ResolvePluginAssembly(object sender, ResolveEventArgs args)
{
var asmName = new AssemblyName(args.Name).Name + ".dll";
var assemblyFiles = Directory.EnumerateFiles(PluginBasePath, "*.dll", SearchOption.AllDirectories);
var asmFile = assemblyFiles.FirstOrDefault(fn => string.Compare(Path.GetFileName(fn), asmName, true) == 0);
if (string.IsNullOrEmpty(asmFile))
return null;
return Assembly.LoadFile(asmFile);
}
}
(Usings for the above: System.IO, System.Reflection, System.Linq)
Call Init with the base path to your plugins folder. When you try to reference an assembly that isn't loaded yet it will search for the first file that matches the base name of the assembly with dll appended. For instance, the NAudio assembly will match the first file named NAudio.dll. It will then load and return the assembly.
No checking is done in the above code on the version, etc. and no preference is given to the current plugin's folder.
I'm having a very hard time trying to access a custom configuration section in my config file.
The config file is being read from a .dll that is loaded as a plug-in. I created the Configuration and necessary code using the Configuration Section Designer VS addin.
The namespace is 'ImportConfiguration'. The ConfigurationSection class is 'ImportWorkflows'. The assembly is ImportEPDMAddin.
The xml:
<configSections>
<section name="importWorkflows" type="ImportConfiguration.ImportWorkflows, ImportEPDMAddin"/>
</configSections>
Whenever I try to read in the config, I get the error:
An error occurred creating the configuration section handler for importWorkflows: Could not load file or assembly 'ImportEPDMAddin.dll' or one of its dependencies. The system cannot find the file specified.
The dll will not reside in the same directory as the executable as the software that loads the plugin places the dll and it's dependencies in it's own directory. (I can't control that.)
I edited the code for the singleton instance to the following:
string path = System.Reflection.Assembly.GetCallingAssembly().CodeBase;
path = path.Replace("file:///", "");
System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(path);
return configuration.GetSection(ImportWorkflowsSectionName) as ImportConfiguration.ImportWorkflows;
I have also tried using a simple NameValueFileSectionHandler as well, but I get an exception saying that it can't load file or assembly 'System'.
I have read numerous blog posts and articles and it sounds like it is possible to read a config file in for a dll, but I just can't get it to work. Any ideas? Thanks.
Unfortunately, you will need to either have the ImportEPDMAddin assembly residing in the same folder as your executable, residing in the .Net framework folder related to the .Net framework you are using (i.e., C:\Windows\Microsoft.NET\Framework\v2.0.50727), or registered in the Global Assembly Cache.
The only other option is, if you know the path to the assembly that contains the configuration handler's defining class, you can load it without a reference with something like this:
//Class global
private Assembly configurationDefiningAssembly;
protected TConfig GetCustomConfig<TConfig>(string configDefiningAssemblyPath,
string configFilePath, string sectionName) where TConfig : ConfigurationSection
{
AppDomain.CurrentDomain.AssemblyResolve += new
ResolveEventHandler(ConfigResolveEventHandler);
configurationDefiningAssembly = Assembly.LoadFrom(configDefiningAssemblyPath);
var exeFileMap = new ExeConfigurationFileMap();
exeFileMap.ExeConfigFilename = configFilePath;
var customConfig = ConfigurationManager.OpenMappedExeConfiguration(exeFileMap,
ConfigurationUserLevel.None);
var returnConfig = customConfig.GetSection(sectionName) as TConfig;
AppDomain.CurrentDomain.AssemblyResolve -= ConfigResolveEventHandler;
return returnConfig;
}
protected Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args)
{
return configurationDefiningAssembly;
}
Make sure you handle the AssemblyResolve event, as this will throw an exception without it.
In your main applications config file, add the following (where plugins is the folder for your assembly to load from. You can use multiple paths semi-colon separated.
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath=".;.\Plugins"/>
</assemblyBinding>
</runtime>
Taken from http://msdn.microsoft.com/en-us/library/823z9h8w%28v=vs.90%29.aspx
To expand on AJ's excellent answer, here is a custom class to assist with the overhead of registering and removing the global event.
public sealed class AddinCustomConfigResolveHelper : IDisposable
{
public AddinCustomConfigResolveHelper(
Assembly addinAssemblyContainingConfigSectionDefinition)
{
Contract.Assert(addinAssemblyContainingConfigSectionDefinition != null);
this.AddinAssemblyContainingConfigSectionDefinition =
addinAssemblyContainingConfigSectionDefinition;
AppDomain.CurrentDomain.AssemblyResolve +=
this.ConfigResolveEventHandler;
}
~AddinCustomConfigResolveHelper()
{
this.Dispose(false);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool isDisposing)
{
AppDomain.CurrentDomain.AssemblyResolve -= this.ConfigResolveEventHandler;
}
private Assembly AddinAssemblyContainingConfigSectionDefinition { get; set; }
private Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args)
{
// often the name provided is partial...this will match full or partial naming
if (this.AddinAssemblyContainingConfigSectionDefinition.FullName.Contains(args.Name))
{
return this.AddinAssemblyContainingConfigSectionDefinition;
}
return null;
}
}
I would suggest creating an instance in a using statement, like so:
// you'll need to populate these two variables
var configuration = GetConfiguration();
var assembly = GetAssemblyContainingConfig();
using(new AddinCustomConfigResolveHelper(assembly))
{
return (MyConfigSection)configuration.GetSection("myConfigSection");
}
Have you made sure that DLL is loaded first? Perhaps with Assembly.LoadFile("PATH")?
If you can't get the classes in System.Configuration to work properly, you can always fall back on using XmlDocument to manually parse the configuration file. Use XPaths to make getting the data easier. For example (assuming your path variable above):
var document = new XmlDocument();
document.Load(path);
var node = document.SelectSingleNode("configuration/importWorkflows/add[#name='KEY']");
// Do whatever with node
Could you verify that the probing paths are setup correctly in your Host application's config file? It is possible that a needed reference is not being loaded in your current application domain.
Assembly Binding ->Probing
Had to use the fully qualified type string of my module/plugin assembly, which is in a probing directory, so it could be located. Using EntityFramework as an example...
Incorrect:
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework"
Correct
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
I tried AJ's answer, with rileywhite's supplement but I found that did not work for me.
In my scenario, the custom ConfigurationSection class was already in the currently-executing assembly, and trying to load it causes a stack overflow. I also did not want to put it in GAC even though it did resolve the problem as reported by the OP.
In end, I found this to work well enough for my purpose. Maybe others will find it useful:
public class CustomConfigurationSection : ConfigurationSection {
public CustomConfigurationSection()
{
var reader = XmlReader.Create(<path to my dll.config>);
reader.ReadToDescendant("CustomConfigurationSection");
base.DeserializeElement(reader,false);
}
// <rest of code>
}