I tied to create simple program Console App C# .NET 4.0 to load DLL file remotely.
My code works as expected on load dll that on the local computer but I got problem resolve dll when trying to load remotely.
I have no idea to handle this since I can't find any code example that load dll remotely.
The error I got as following.
Could not load file or assembly 'http://codesanook.cloudapp.net/dll/ZupZip.Lib.I
nterfaces.dll' or one of its dependencies. Operation is not supported. (Exceptio
n from HRESULT: 0x80131515)
at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String cod
eBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark&
stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntro
spection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String code
Base, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& s
tackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntros
pection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName as
semblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMar
k& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIn
trospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Ev
idence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm,
Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackM
ark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at LoadDllRemotely.Proxy.GetObject[T](String assemblyPath, String fullTypeNam
e, String[] referencedAssembliesPath) in C:\Projects\LoadDllRemotely\LoadDllRemo
tely\Program.cs:line 102
Unhandled Exception: System.NullReferenceException: Object reference not set to
an instance of an object.
at LoadDllRemotely.Program.LoadRemotely() in C:\Projects\LoadDllRemotely\Load
DllRemotely\Program.cs:line 74
at LoadDllRemotely.Program.Main(String[] args) in C:\Projects\LoadDllRemotely
\LoadDllRemotely\Program.cs:line 28
Press any key to continue . . .
This is my implementation that load dll remotely with new AppDomain
using System;
using System.IO;
using System.Reflection;
using ZupZip.Lib.Interfaces;
namespace LoadDllRemotely
{
public class Program
{
private const string ASSEMBLY_PATH =
#"C:\Projects\LoadDllRemotely\ZupZip.Lib\bin\Debug\ZupZip.Lib.dll";
private const string ASSEMBLY_URL =
#"http://codesanook.cloudapp.net/dll/ZupZip.Lib.dll";
private const string REFERENCED_ASSEMBLY3_URL =
#"http://codesanook.cloudapp.net/dll/ZupZip.Lib.Interfaces.dll";
private const string REFERENCED_ASSEMBLY2_URL =
#"http://codesanook.cloudapp.net/dll/system.core.dll";
private const string REFERENCED_ASSEMBLY1_URL =
#"http://codesanook.cloudapp.net/dll/mscorlib.dll";
public static void Main(string[] args)
{
//LoadLocally();
LoadRemotely();
}
public static void appDomain_DomainUnload(object sender, EventArgs e)
{
Console.WriteLine("domain loaded sender: {0}",
sender.GetType().FullName);
}
public static void LoadLocally()
{
var appDomain = AppDomain.CreateDomain("dynamicDll");
appDomain.DomainUnload += new EventHandler(appDomain_DomainUnload);
var proxy = (Proxy)appDomain.CreateInstanceAndUnwrap(
typeof(Proxy).Assembly.FullName,
typeof(Proxy).FullName);
var calculator = proxy.GetObject<IGradeCalculator>(
ASSEMBLY_PATH,
"ZupZip.Lib.GradeCalculator");
var score = 80;
Console.WriteLine("you got grad: {0} from score: {1}", calculator.GetGradeForScore(score), score);
AppDomain.Unload(appDomain);
File.Delete(ASSEMBLY_PATH);//you can delete referece dll after remove
}
public static void LoadRemotely()
{
//app domain setup
//load as byte array
var appDomain = AppDomain.CreateDomain("dynamicDll");
appDomain.DomainUnload += new EventHandler(appDomain_DomainUnload);
var proxy = (Proxy)appDomain.CreateInstanceAndUnwrap(
typeof(Proxy).Assembly.FullName,
typeof(Proxy).FullName);
var calculator = proxy.GetObject<IGradeCalculator>(
ASSEMBLY_URL,
"ZupZip.Lib.GradeCalculator",
REFERENCED_ASSEMBLY3_URL);
var score = 80;
Console.WriteLine("you got grad: {0} from score: {1}", calculator.GetGradeForScore(score), score);
AppDomain.Unload(appDomain);
}
}
public class Proxy : MarshalByRefObject
{
public T GetObject<T>(
string assemblyPath,
string fullTypeName,
params string[] referencedAssembliesPath) where T : class
{
try
{
//find reference
var assemblyToLoad = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
AssemblyName[] referencedAssemblies = assemblyToLoad.GetReferencedAssemblies();
//foreach (var referencedAssembly in referencedAssemblies)
//{
// Console.WriteLine("referenceAssemblyName: {0}", referencedAssembly.Name);
// Assembly.Load(referencedAssembly.Name);
//}
//solve reference assembly
foreach (var referencedAssemblyPath in referencedAssembliesPath)
{
Assembly.LoadFrom(referencedAssemblyPath);
}
//this dll will load in new domain
var assembly = Assembly.LoadFrom(assemblyPath);
var type = assembly.GetType(fullTypeName);
var obj = (T)Activator.CreateInstance(type);
return obj;
}
catch (Exception ex)
{
// throw new InvalidOperationException(ex);
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
return null;
}
}
}
}
I also add this source code to my open source on Bitbuckget
enter link description here
Fixed
just add this configuration to App.Config to run in full trust
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<loadFromRemoteSources enabled="true"/>
</runtime>
</configuration>
and I also update this code at
https://bitbucket.org/theeranitp/loaddllremotely
Related
I do web. service that load assembly file by input parameter.
Then in assembly will try to find a specific type (inherited from specific interface), create an instance and returns the result of the method.
I need to make the call to the assembly was again released.
From the input parameters of the method I find the path to the the assembly in web.config. and try to load it.
This is the code that works:
[WebMethod]
public String[] GetData(String confKey)
{
var assemblyPath = ConfigurationManager.AppSettings[confKey];
var assembly = Assembly.LoadFrom(assemblyPath);
List<String> retVals = new List<String>();
foreach (var t in assembly.GetTypes())
{
if (t.ImplementsInterface(typeof(IMyServiceProvider)))
{
IMyServiceProvider objectInstance = Activator.CreateInstance(t) as IMyServiceProvider;
retVals.Add(objectInstance.GetData());
}
}
return retVals.ToArray();
}
But this way I can delete the loaded assembly or replace it because the file is "locked".
So I tried to go a different way and load the assembly into own AppDomain like this:
[WebMethod]
public String[] GetData(String confKey)
{
var assemblyPath = ConfigurationManager.AppSettings[confKey];
var tmp = String.Concat("AppDomain", Guid.NewGuid().ToString("N"));
AppDomain dom = AppDomain.CreateDomain(tmp, null, AppDomain.CurrentDomain.SetupInformation);
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = assemblyPath;
Assembly assembly = dom.Load(assemblyPath);
List<String> retVals = new List<String>();
foreach (var t in assembly.GetTypes())
{
if (t.ImplementsInterface(typeof(IMyServiceProvider)))
{
IMyServiceProvider objectInstance = Activator.CreateInstance(t) as IMyServiceProvider;
retVals.Add(objectInstance.GetData());
}
}
AppDomain.Unload(dom);
return retVals.ToArray();
}
But this solution is thrown Exception:
Could not load file or assembly 'NameOfMyAssembly' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)- at System.Reflection.AssemblyName.nInit(RuntimeAssembly& assembly, Boolean forIntrospection, Boolean raiseResolveEvent)
at System.Reflection.RuntimeAssembly.CreateAssemblyName(String assemblyString, Boolean forIntrospection, RuntimeAssembly& assemblyFromResolveEvent)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.AppDomain.Load(String assemblyString)
at System.AppDomain.Load(String assemblyString)
Why the first solution assembly loads without problem, and the second throws an error ?
Thanks
dom.Load(string) method tries to load the assembly by its full name which consists of assembly name, version, culture info and public key. CLR search the assemby in GAC and application's directory. Also you could set additional searching paths with .config file (app.config or ) and probing element. In your case as I understand assemblyPath is a path to the assembly you whant to load and it isn't what need to pass as parameter. I used next code to load assemblies in created domain:
var domain = AppDomain.CreateDomain("Plugin domain"); // Domain for plugins
domain.Load(typeof(IPlugin).Assembly.FullName); // Load assembly containing plugin interface to domain
// ...
var asm = Assembly.LoadFrom(pluginFile);
foreach (var exportedType in asm.GetExportedTypes())
{
if (!typeof (IPlugin).IsAssignableFrom(exportedType))
continue; // Check if exportedType implement IPlugin interface
domain.Load(asm.FullName); // If so load this dll into domain
// ...
}
As all plugins lies in "\Plugins" directory relatively application directory I also added .config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="Plugins"/>
</assemblyBinding>
</runtime>
</configuration>
Pay attantion that if you whant to use dom.Load(AssemblyName) with specified only CodeBase property you must set it in Uri format (i.e. "file:///D:/Dir/...") and I think these assemblies have to be strongly named if they are not in the current application’s folder.
Also as I see you are usig Activator.CreateInstance() to create objects. In this case although you load assembly in created domain you create objects in current domain and all code of this objects be executed in current domain too. To create and execute code in a separate domain you should use appDomain.CreateInstanceAndUnwrap() method (link)
I have a dotnet script which is for encryption and decryption. I have to pass the parameters for the setvalues function in installshield. How can I achieve this? Dotnet code is as follows. I have the assembly (.dll) file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Security;
using System.Xml;
using System.Collections.Specialized;
namespace EncryptionDecryption
{
public class EncrptionHelper
{
#region Member variables
static byte[] entropy = { 0, 8, 2, 3, 5 };
#endregion
#region Public Methods
public static void SetValue(string configFilePathName, string appSettingKey, string appSettingValue)
{
appSettingValue = EncryptString(ToSecureString(appSettingValue));
SetSetting(appSettingKey, appSettingValue, configFilePathName);
}
public static string GetValue(string configFilePathName, string appSettingKey)
{
string value = GetSetting(appSettingKey, configFilePathName);
value = ToInsecureString( DecryptString(value));
return value;
}
#endregion
#region Private Methods
private static bool SetSetting(string Key, string Value, string configFilePath)
{
bool result = false;
try
{
// System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(configFilePath);
// config.AppSettings.File = configFilePath;
// config.AppSettings.Settings[Key].Value = Value;
// config.Save(ConfigurationSaveMode.Modified);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(configFilePath);
xmlDoc.SelectSingleNode("//appSettings/add[#key='" + Key +"']").Attributes["value"].Value = Value;
xmlDoc.Save(configFilePath);
ConfigurationManager.RefreshSection("appSettings");
result = true;
}
finally
{ }
return result;
}
private static string GetSetting(string Key, string configFilePath)
{
string result = null;
try
{
XmlDocument appSettingsDoc = new XmlDocument();
appSettingsDoc.Load(configFilePath);
XmlNode node = appSettingsDoc.SelectSingleNode("//appSettings");
XmlElement value = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='" + Key + "']"));
result = (value.GetAttribute("value").ToString());
}
finally
{ }
return result;
}
private static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
private static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
return returnValue;
}
private static string EncryptString(System.Security.SecureString input)
{
byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)), entropy, System.Security.Cryptography.DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encryptedData);
}
private static SecureString DecryptString(string encryptedData)
{
try
{
byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
Convert.FromBase64String(encryptedData),
entropy,
System.Security.Cryptography.DataProtectionScope.CurrentUser);
return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData));
}
catch
{
return new SecureString();
}
}
#endregion
}
}
Update: Action start 14:31:36: Encryption.
MSI (c) (84:40) [14:31:36:525]: Invoking remote custom action. DLL: C:\Users\<username>\AppData\Local\Temp\MSIE259.tmp, Entrypoint: m1
InstallShield: Attempting to load through CLR 4 APIs...
InstallShield: Getting meta host...
InstallShield: Enumerating available runtimes...
InstallShield: Highest available runtime: v4.0.30319
InstallShield: Trying to use highest runtime...
InstallShield: Using highest version runtime...
InstallShield: Loading assembly Security.Encryption from resource 4097
InstallShield: Calling method with parameters [(System.String)C:\Program Files (x86)\<Installdir>\<configfilename>.config, (System.String)VWFPassword, (System.String)]
InstallShield: Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Program Files (x86)\<Installdir>\<configfilename>.config'.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials, IWebProxy proxy, RequestCachePolicy cachePolicy)
at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn)
at System.Xml.XmlTextReaderImpl.OpenUrlDelegate(Object xmlResolver)
at System.Threading.CompressedStack.runTryCode(Object userData)
at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.CompressedStack.Run(CompressedStack compressedStack, ContextCallback callback, Object state)
at System.Xml.XmlTextReaderImpl.OpenUrl()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.Load(String filename)
at Security.Encryption.EncrptionHelper.SetSetting(String appSettingKey, String appsettingValue, String configFilePathName)
at Security.Encryption.EncrptionHelper.SetValue(String configFilePathName, String appSettingKey, String appSettingValue)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at InstallShield.ClrHelper.CustomActionHelper.CallMethod(EntryPointInfo info)
at InstallShield.ClrHelper.CustomActionHelper.RunAction(UInt32 installHandle, Int32 entryNumber, Int64 instanceHandle)
InstallShield: Managed code threw an unhandled exception.
This is the error I receive after doing all that is mentioned in the screenshots below and doing some R&D. The directory mentioned "C:\Program Files (x86)\\.config" exists when the encryption custiom action is being called but it throws an exception.
Yes, it can be done with following steps:
1- write your required functionality in c# installer class (make sure your are using installer class)
2- Compile and add your dll into installshield (recomended create a separate component for this dll)
3- Select component view -> select above component and go to .Net settings section, set the ".Net Installer class" to true. Set the ".net installer class parameters"
Parameters are passed as key/value pair e.g
/targetDirectory="[INSTALLDIR]\"
All steps are same, just added screenshots.
Create a dll with an installer class and your encrypt/decrypt class.
Add dll and config file to component(above mentioned), if config file is already added to some other component then its fine. no need to add again.
I have added and retrieved INSTALLDIR variable as argument which is predefined. if you want to receive some input from user (from some custom textboxes) then you will need to define your own variables to store and pass values as arguments.
Creating dll with installer class and your requred logic for other task
Creating component and adding files
Mark the dll as installer class and pass arguments
Here goes installer class:
using System;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
using System.Configuration.Install;
using System.Collections.Generic;
namespace EncryptionDecryption
{
[RunInstaller(true)]
public class InstallerClassDemo : Installer
{
private string installationDirectory=string.Empty;
private string testString=string.Empty ;
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
//For testing purpose only.. work only in debug mode when pdb files are deployed as well.
//Debugger.Break();
installationDirectory = Context.Parameters["INSTALLDIR"];
//I believe, the config file must be located in the installation directory if so, then use the following way to compute path
string configFilePath = Path.Combine(installationDirectory, "myConfigFile.config");
EncrptionHelper.SetValue(configFilePath, "testKey", "testValue");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
protected override void OnCommitted(System.Collections.IDictionary savedState)
{
base.OnCommitted(savedState);
}
public override void Uninstall(System.Collections.IDictionary savedState)
{
base.Uninstall(savedState);
}
}
}
I think installshield cannot (or need extra work) for read your assemblies, but you can run simple console application which consume your assemblies from installscript and passing parameter from installshield.
Create simple console application
Include console application on Support Files
Copy to installation folder or assemblies location, so console application can access your assemblies
Launch from installscript using launchappandwait
If consoleapp.exe not use anymore, just delete it.
I have a solution with several projects, a main project, a globalization project and a test project.
When code in the main project retreives a message from the Messages.de.resx file of the globalization project everything works fine.
But when I copy the same code to the test project, I get a MissingManifestResourceException telling me no resources were found for the specified or neutral culture:
System.Resources.MissingManifestResourceException ist aufgetreten.
Message=Für die angegebene Kultur oder die neutrale Kultur konnten
keine Ressourcen gefunden werden. Stellen Sie sicher, dass
EGR_IQone_Globalization.Messages.resources beim Kompilieren richtig in
die Assembly EGR_IQone_Globalization eingebettet wurde, oder dass die
erforderlichen Satellitenassemblys geladen werden können und
vollständig signiert sind. Source=mscorlib StackTrace:
bei System.Resources.ManifestBasedResourceGroveler.HandleResourceStreamMissing(String
fileName)
bei System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo
culture, Dictionary`2 localResourceSets, Boolean tryParents, Boolean
createIfNotExists, StackCrawlMark& stackMark)
bei System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo
requestedCulture, Boolean createIfNotExists, Boolean tryParents,
StackCrawlMark& stackMark)
bei System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo
culture, Boolean createIfNotExists, Boolean tryParents)
bei System.Resources.ResourceManager.GetString(String name, CultureInfo culture)
bei System.Resources.ResourceManager.GetString(String name)
bei EGR_IQone_Globalization.UserMessage.GetMessage(String msgID, String[] arguments) in
C:\projects\EGR_IQoneH\EGR_IQone\EGR_IQone_Globalization\UserMessage.cs:Zeile
28. InnerException:
Normally, the code works just using the .resx file and even using resgen to compile it into a .resources file changes nothing.
I thought it might have to do with the ResourceManager or the specified Assembly, but I could not see any difference between the call from the main project and the call from the test project.
This is the code:
public static class UserMessage
{
private static ResourceManager _resourceManager;
static UserMessage()
{
string baseName = Assembly.GetAssembly(typeof(UserMessage)).GetName().Name + ".Messages.de";
Console.WriteLine(baseName);
_resourceManager = new ResourceManager(baseName, Properties.GlobalizationAssembly);
}
public static string GetMessage(string msgID, params string[] arguments)
{
string msg = "";
string error = "[Message Error] cannot read Message " + msgID;
try
{
//DefaultLanguage = 'de'
//using the GetString overload with or without CultureInfo paramter makes no difference
msg = _resourceManager.GetString(msgID, new CultureInfo(Properties.DefaultLanguage));
for (int i = 0; i < arguments.Length; i++)
{
msg = msg.Replace("{" + i.ToString() + "}", arguments[i]);
}
}
catch (Exception ex)
{
Console.WriteLine(error + "\r\n" + ex.ToString());
return error;
}
return msg;
}
}
http://pastebin.com/L0YNxyfK
Thanks!
I've had the same error - it suddenly occurred even though the application had been running for a while.
It helped to set the Thread.CurrentThread.CurrentUICulture before getting the resource.
Try the following or something similar:
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
msg = _resourceManager.GetString(msgID);
I am trying to load a strongly named assembly that is located at a user-defined location into an AppDomain using this code:
AppDomainSetup ads1 = new AppDomainSetup();
if (ads1.PrivateBinPath != null)
{
ads1.PrivateBinPath += ads1.PrivateBinPath.Length == 0 ? "" : Path.PathSeparator.ToString();
}
ads1.PrivateBinPath += #"c:\work\abc1";
sandbox1 = AppDomain.CreateDomain("sandbox1", null, ads1);
Object o1 = sandbox1.CreateInstanceFromAndUnwrap(#"abc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f10808f3df0adc34", "Abc.Def");
When I run I get this error:
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'file:///C:\Users\gel\Documents\Visual Studio 2012\Projects\ConsoleApplicat
ion1\ConsoleApplication1\bin\Debug\abc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f10808f3df0adc34' or one of its dependencies. The system cannot find the fil
e specified.
at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stack
Mark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& st
ackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& st
ackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boole
an forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile, Evidence securityEvidence)
at System.Activator.CreateInstanceFromInternal(String assemblyFile, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, C
ultureInfo culture, Object[] activationAttributes, Evidence securityInfo)
at System.AppDomain.CreateInstanceFrom(String assemblyFile, String typeName)
at System.AppDomain.CreateInstanceFromAndUnwrap(String assemblyName, String typeName)
at System.AppDomain.CreateInstanceFromAndUnwrap(String assemblyName, String typeName)
at ConsoleApplication1.Program.Main(String[] args) in c:\Users\gel\Documents\Visual Studio 2012\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs:li
ne 69
It is as though the AppDomain is not looking in the PrivateBinPath at all. What am I not doing right? I've double checked in an Explorer window and I can see the assembly at the location that I specified in the PrivateBinPath. It works fine if I just do Assembly.LoadFile and specify the right path, but that'd defeating the purpose of trying to load it in another AppDomain.
I've modified your code and this works just great. See the changes you needs to be done.
AppDomainSetup ads1 = new AppDomainSetup();
if (ads1.PrivateBinPath != null)
{
ads1.PrivateBinPath += ads1.PrivateBinPath.Length == 0 ? "" : Path.PathSeparator.ToString();
}
ads1.PrivateBinPath += #"D:\ConsoleApplication1\ClassLibrary1\bin\debug";
AppDomain sandbox1 = AppDomain.CreateDomain("sandbox1", null, ads1);
Object o1 = sandbox1.CreateInstanceFromAndUnwrap(#"ClassLibrary1.dll", "ClassLibrary1.Class1");
I belive it fails to load that assembly into your current AppDomain, not to the new one (where it likley loaded ok).
The behavior sometimes called "leaking types to aother domain" and casued by attempt to use the created object directly. To work around it one need to create class completely in the other AppDomain (i.e. by running some custom code that deal with creation) and than exposing only interface/classes known to both domain. Check out Unloadable plugins for details.
Short portion of code adopted from the article - create RemoteLoader class in other AppDomain with CreateInstanceFromAndUnwrap and use that object to load/manage other types in the new AppDomain.
public class RemoteLoader : MarshalByRefObject
{
public void Load(string assemblyName, string typeName)
{
object instance = Activator.CreateInstance(assemblyName, typeName);
//Do something with instance, or return shared interface of it.
}
}
Side note: unless you doing it for education purposes consider using existing plugin frameworks like MEF.
I've got an assembly of domain objects. It WAS called company.xpo.domain (it was named that by the contractor that initially named the project, and they are longer with us - we own the software). I did a global rename of the namespace to xpo.domain and I changed the default namespace in the designer to xpo.domain.
I also did a find in visual studio on the entire solution for "company" and found nothing.
My problem goes like this:
in the assembly there is a user object that has a static method "Login" which takes a username and a password, checks the db for the name/password and returns null if nothing was found.
IN THAT STATIC METHOD, it throws a FileNotFoundException for the company.xpo.domain assembly. This is confusing to me because, the code that's throwing the exception, exists in the assembly that it's looking for (but it's looking for the previous name of the assembly).
EDIT
Here is the stack trace. I've just done a rename on the name of the software and the name of the assembly for the purpose of security.
System.IO.FileNotFoundException occurred
Message="Could not load file or assembly 'company.XPO.domain' or one of its dependencies. The system cannot find the file specified."
Source="mscorlib"
FileName="company.XPO.domain"
FusionLog="=== Pre-bind state information ===
LOG: User = STOONP001\\Administrator
LOG: DisplayName = company.XPO.domain\n (Partial)
LOG: Appbase = file:///C:/Documents and Settings/Administrator/Desktop/softwareName/softwareName/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : DevExpress.Data.v9.2, Version=9.2.5.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\\Documents and Settings\\Administrator\\Desktop\\softwareName\\softwareName\\bin\\Debug\\softwareName.vshost.exe.config
LOG: Using machine configuration file from c:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727\\config\\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Documents and Settings/Administrator/Desktop/softwareName/softwareName/bin/Debug/company.XPO.domain.DLL.
LOG: Attempting download of new URL file:///C:/Documents and Settings/Administrator/Desktop/softwareName/softwareName/bin/Debug/company.XPO.domain/company.XPO.domain.DLL.
LOG: Attempting download of new URL file:///C:/Documents and Settings/Administrator/Desktop/softwareName/softwareName/bin/Debug/company.XPO.domain.EXE.
LOG: Attempting download of new URL file:///C:/Documents and Settings/Administrator/Desktop/softwareName/softwareName/bin/Debug/company.XPO.domain/company.XPO.domain.EXE."
StackTrace:
at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
InnerException
EDIT 2
The call stack, if it helps, is here. It seems to appear that devexpress.data.utils is throwing the error, but I have no control over that class (if it is in fact a problem with that assembly).
mscorlib.dll!System.Reflection.Assembly.nLoad(System.Reflection.AssemblyName fileName, string codeBase, System.Security.Policy.Evidence assemblySecurity, System.Reflection.Assembly locationHint, ref System.Threading.StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection) + 0x2c bytes
mscorlib.dll!System.Reflection.Assembly.LoadWithPartialNameInternal(string partialName, System.Security.Policy.Evidence securityEvidence = null, ref System.Threading.StackCrawlMark stackMark = LookForMyCaller) + 0x6b bytes
mscorlib.dll!System.Reflection.Assembly.LoadWithPartialName(string partialName) + 0x1b bytes
DevExpress.Data.v9.2.dll!DevExpress.Data.Utils.Helpers.LoadWithPartialName(string partialName = "company.XPO.domain") + 0x1f bytes
DevExpress.Data.v9.2.dll!DevExpress.Xpo.Helpers.XPTypeActivator.GetType(string assemblyName = "company.XPO.domain", string typeName = "company.XPO.domain.customer") + 0xd0 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Metadata.ReflectionDictionary.ResolveClassInfoByName(string assemblyName = "company.XPO.domain", string typeName = "company.XPO.domain.customer") + 0x50 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Metadata.ReflectionDictionary.QueryClassInfo(string assemblyName = "company.XPO.domain", string className = "company.XPO.domain.customer") + 0xde bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.XPObjectType.TypeClassInfo.get() + 0x55 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.XPObjectType.IsValidType.get() + 0x1f bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Helpers.XPObjectTypesManager.FillLoadedTypes(System.Collections.ICollection objectTypesList = Count = 23) + 0xfa bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Helpers.XPObjectTypesManager.GetAllTypes() + 0x278 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Helpers.XPObjectTypesManager.EnsureIsTypedObjectValid() + 0x1e bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Helpers.ObjectCollectionLoader.InternalLoadData(DevExpress.Xpo.ObjectsQuery[] queries = {DevExpress.Xpo.ObjectsQuery[1]}) + 0x5a bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Helpers.ObjectCollectionLoader.LoadObjects(DevExpress.Xpo.ObjectsQuery[] queries = {DevExpress.Xpo.ObjectsQuery[1]}) + 0xda bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Session.GetObjects(DevExpress.Xpo.ObjectsQuery[] queries = {DevExpress.Xpo.ObjectsQuery[1]}) + 0x58 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Session.GetObjects(DevExpress.Xpo.ObjectsQuery query = {DevExpress.Xpo.ObjectsQuery}) + 0x55 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Session.GetObjects(DevExpress.Xpo.Metadata.XPClassInfo classInfo = {XPO.domain.sys_user}, DevExpress.Data.Filtering.CriteriaOperator criteria = {[Username] = 'username' And [Password1] = 'password'}, DevExpress.Xpo.SortingCollection sorting = null, int topSelectedRecords = 1, bool selectDeleted = false, bool force = false) + 0x9b bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Session.InternalFindAndLoad(DevExpress.Xpo.Metadata.XPClassInfo baseType = {XPO.domain.sys_user}, DevExpress.Data.Filtering.CriteriaOperator criteria = {[Username] = 'username' And [Password1] = 'password'}, bool selectDeleted = false) + 0x38 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Session.FindObject(DevExpress.Xpo.Metadata.XPClassInfo classInfo = {XPO.domain.sys_user}, DevExpress.Data.Filtering.CriteriaOperator criteria = {[Username] = 'username' And [Password1] = 'password'}, bool selectDeleted = false) + 0x2d bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Session.FindObject(System.Type classType = {Name = "sys_user" FullName = "XPO.domain.sys_user"}, DevExpress.Data.Filtering.CriteriaOperator criteria = {[Username] = 'username' And [Password1] = 'password'}, bool selectDeleted = false) + 0x52 bytes
DevExpress.Xpo.v9.2.dll!DevExpress.Xpo.Session.FindObject<XPO.domain.sys_user>(DevExpress.Data.Filtering.CriteriaOperator criteria = {[Username] = 'username' And [Password1] = 'password'}) + 0x57 bytes
Note: I have created a case with DevExpress as well, just in case. I'm totally stumped.
I would definitely need to see a stack trace and/or code to really know for sure, but it sounds to me like you might have some kind of circular reference in your assemblies and one of them is referencing your old assembly. But that's completely just a stab in the dark.
If you can and if applicable, I'd check the code associated with any Typed DataSets you might have; I've had had problems renaming namespaces within Typed DataSet classes. I've had to go in and had to do 'search and replaces' manually.
Again, this may not be revelant for you.
Edit--
Another possibility:
Any chance there's something in your GAC that references the old assembly by name?