Invoking remote methods is loading the remote assembly in parent appdomain - c#

I think I've determined that even though I'm loading assemblies in a MarshalByRefObject in a new AppDomain that the assemblies are also getting loaded into the parent domain.
Here's my Assembly structure (arrows indicate dependency):
MainAssembly -> CommonInterfaceAssembly <- ExtensionAssembly
In the parent AppDomain I'm doing this:
var loader = (ExtensionLoader)extDomain.CreateInstanceAndUnwrap (Assembly.GetExecutingAssembly().FullName, "ExtensionLoader");
loader.loadExtensions (this);
and the Loader class is:
class ExtensionLoader : MarshalByRefObject
{
public List<IExtension> loadExtensions (ExtensionMgr mgr)
{
// Delegate to Addins to return the list of extensions
AddinManager.Initialize ();
AddinManager.Registry.Update ();
AddinManager.GetExtensionObjects<IExtension> ();
var extensions = new List<IExtension> (AddinManager.GetExtensionObjects<IExtension> ());
foreach (var ext in extensions) {
ext.Initialize (mgr);
}
return extensions;
}
}
I don't know if it's relevant to the question, but I am using Mono.Addins to load the extensions in the new AppDomain so I've left that code in. From what I can tell though things work fine up to the point where I invoke the Initialize method on each of the extensions.
So I have ran this scenario with the ExtensionAssembly in the same directory as the main executable and in a separate 'extensions' directory. What's curious to me is that when I invoke ext.Initialize either the ExtensionAssembly gets loaded in the parent AppDomain (if it exists in the same directory), or I get the below stack trace if not. Any ideas why?
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke (System.Runtime.Remoting.Proxies.RealProxy rp, IMessage msg, System.Exception& exc, System.Object[]& out_args) [0x001f0] in /home/tim/tmp/mono-2.10.8/mcs/class/corlib/System.Runtime.Remoting.Proxies/RealProxy.cs:247
Exception rethrown at [1]:
---> System.IO.FileNotFoundException: Could not load file or assembly 'Extensions, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
File name: 'Extensions, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
at System.AppDomain.Load (System.String assemblyString, System.Security.Policy.Evidence assemblySecurity, Boolean refonly) [0x00047] in /home/tim/tmp/mono-2.10.8/mcs/class/corlib/System/AppDomain.cs:785
at System.AppDomain.Load (System.String assemblyString) [0x00000] in /home/tim/tmp/mono-2.10.8/mcs/class/corlib/System/AppDomain.cs:762

Related

C# appDomain failed to work for "CodeAccessPermission" reason, why?

I'm trying C# appdomain on win10 using vs2017, I've got this quick example. I've a directory called c:\git, I can create files under this directory with C# app, but when I tried app domain, it throws exception, my code as below:
class UseAppDomain
{
public static void Test()
{
var perm = new PermissionSet(PermissionState.None);
perm.AddPermission(
new SecurityPermission(SecurityPermissionFlag.Execution));
perm.AddPermission(
new FileIOPermission(FileIOPermissionAccess.NoAccess, #"c:\"));
var setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
AppDomain secureDomain = AppDomain.CreateDomain("secure", null, setup, perm);
ThirdParty third = new ThirdParty();
Type thirdParty = typeof(ThirdParty);
secureDomain.
CreateInstanceAndUnwrap(thirdParty.Assembly.FullName,
thirdParty.FullName); //exception!!!!!!!!!!
AppDomain.Unload(secureDomain);
}
}
[Serializable]
class ThirdParty
{
public ThirdParty()
{
Console.WriteLine("3p loadling");
System.IO.File.Create(#"c:\git\test.txt");//Try to create file failed!
}
}
The exception message is:
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark)
at System.Security.CodeAccessPermission.Demand()
... ...
I don't quite get what problem my program has, how to fix this issue?
Thanks.
If you want to create files from a partially trusted domain you need to use FileIOPermissionAccess.Write instead. Or FileIOPermissionAccess.AllAccess if you want to allow also reading and directory content discovery.
Side note:
You use the CreateInstanceAndUnwrap for a simple serializable class, which is not derived from MarshalByRefObject. Its effect is that the class will be serialized in the created domain and a copy will be deserialized in the main domain but as you omit the return value it will be dropped anyway.
So either do not unwrap the created object or derive it from the MarshalByRefObject class so its public members can be accessed from the main domain via remoting.

Way to embed/reference another DLL assembly while invoking a method using C# Reflection

Is there anyway to invoke methods using C# Reflection with embedded/reference dlls?
For example consider the following senario.
I have a assembly call User.dll, which have the class as bellow
namespace User
{
public class UserInfo
{
public static string Name = "Username";
}
}
Using the above dll as reference, I can able to compile the following code and access UserInfo.Name variable.
using User;
using System.Windows.Forms;
public class Test
{
public Test()
{
MessageBox.Show("Name : " + UserInfo.Name);
}
}
Consider the above code is in another dll called Test.dll assembly. Using Assembly.LoadFile("Test.dll") and C# Reflection, when I try to invoke the Constructor, getting File not found runtime error.
Error
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'DynamicAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
at Test..ctor()
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
Assembly.LoadFile method only loads the specified file. You need to use Assembly.LoadFrom method in your case. Please check for differences between Assembly.LoadFile and Assembly.LoadFrom
LoadFrom() goes through Fusion and can be redirected to another assembly at a different path but with that same identity if one is already loaded in the LoadFrom context.
LoadFile() doesn't bind through Fusion at all - the loader just goes ahead and loads exactly* what the caller requested. It doesn't use either the Load or the LoadFrom context.
Your executing code sample would be like
static void Main(string[] args)
{
var fileName = ""; //put here test.dll path
Assembly ass = Assembly.LoadFrom(fileName);
var type = ass.GetType("Test.Test");
var test = Activator.CreateInstance(type);
}
I had the same problem.
I just copied the DLL into bin folder of the project.

How can I make SourceAFIS work on Ubuntu?

I am trying to use SourceAFIS 1.7.0 on Ubuntu with mono and get a few error.
1.
$ mono DatabaseAnalyzer.exe
Scanning folder TestDatabase
Running extractor benchmark
Unhandled Exception: System.IO.FileNotFoundException: Could not load
file or assembly 'PresentationCore, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' or one of its dependencies.
File name: 'PresentationCore, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35'
at DatabaseAnalyzer.DatabaseAnalyzer.RunExtractorBenchmark ()
<0x40674790
+ 0x00033> in :0 at DatabaseAnalyzer.DatabaseAnalyzer.RunMatcherBenchmark () <0x40674600 +
0x000eb> in :0
at DatabaseAnalyzer.DatabaseAnalyzer.Run () <0x40642a40 + 0x000bf> in
:0
at DatabaseAnalyzer.DatabaseAnalyzer.Main (System.String[] args)
<0x4063bd50 + 0x00037> in :0
[ERROR] FATAL UNHANDLED EXCEPTION: System.IO.FileNotFoundException:
Could not load file or assembly 'PresentationCore, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its
dependencies.
File name: 'PresentationCore, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35' at
DatabaseAnalyzer.DatabaseAnalyzer.RunExtractorBenchmark () <0x40674790
+ 0x00033> in :0 at DatabaseAnalyzer.DatabaseAnalyzer.RunMatcherBenchmark () <0x40674600 +
0x000eb> in :0
at DatabaseAnalyzer.DatabaseAnalyzer.Run () <0x40642a40 + 0x000bf> in
:0
at DatabaseAnalyzer.DatabaseAnalyzer.Main (System.String[] args)
<0x4063bd50 + 0x00037> in :0
According to https://sourceforge.net/p/sourceafis/discussion/1051112/thread/dd8df289/#a006, WinForms should be applied here instead of WPF and use bitmap class to replace the bitmapimage class of WPF, but I don't know how to do it exactly. Does anybody have such experience?
This is the original function used WPF bitmap class
static MyPerson Enroll(string filename, string name)
{
Console.WriteLine("Enrolling {0}...", name);
// Initialize empty fingerprint object and set properties
MyFingerprint fp = new MyFingerprint();
fp.Filename = filename;
// Load image from the file
Console.WriteLine(" Loading image from {0}...", filename);
BitmapImage image = new BitmapImage(new Uri(filename, UriKind.RelativeOrAbsolute));
fp.AsBitmapSource = image;
// Above update of fp.AsBitmapSource initialized also raw image in fp.Image
// Check raw image dimensions, Y axis is first, X axis is second
Console.WriteLine(" Image size = {0} x {1} (width x height)", fp.Image.GetLength(1), fp.Image.GetLength(0));
// Initialize empty person object and set its properties
MyPerson person = new MyPerson();
person.Name = name;
// Add fingerprint to the person
person.Fingerprints.Add(fp);
// Execute extraction in order to initialize fp.Template
Console.WriteLine(" Extracting template...");
Afis.Extract(person);
// Check template size
Console.WriteLine(" Template size = {0} bytes", fp.Template.Length);
return person;
}
$ mono SourceAFIS.FingerprintAnalysis.exe
The entry point method could not be loaded
How can I fix this with a more meaningful exception?
WinForms should be applied here instead of WPF and use bitmap class to
replace the bitmapimage class of WPF, but I don't know how to do it
exactly. Does anybody have such experience?
Do you know how to program in C# language? What they mean in that forum is that you need to change the code to not use the WPF library, but Windows Forms UI toolkit.
If you get exceptions trying to load "PresentationCore" at runtime, it means it's still trying to load WPF.
Try installing mono-complete package, e.g.
apt-get install mono-complete
Related: Mono, failing to open executable.
Also make sure you've .NET Framework installed, e.g. by using winetricks:
apt-get install winetricks
winetricks dotnet46
See: Could not load file or assembly 'PresentationCore'.
PresentationCore is .NET 4
Further more, you can try the following suggestions:
In IIS try to Enable 32-Bit Applications in the Application Pools's Advanced Settings
Configure authentication as follow:
Disable Anonymous Authentication.
Enable ASP.NET Impersonation.
Enable Windows Authentication.

Reflecting a WinRT executable from a .Net 4.x App

In a console application; If I execute:
Assembly.LoadFrom(#"c:\...\MyWinRTApp.exe")
I get:
System.BadImageFormatException occurred
HResult=-2147024885
Message=Could not load file or assembly 'file:///C:\_...\MyWinRTApp.exe' or one of its dependencies. An attempt was made to load a program with an incorrect format.
Source=mscorlib
Is there any way around this?
EDIT 1
In relation to "Vyacheslav Volkov"'s answer below, I now get a step further, thank you. However I now get a different issue.
"assembly.GetExportedTypes()"
now throws
"Cannot resolve dependency to Windows Runtime type 'Windows.UI.Xaml.Application'. When using the ReflectionOnly APIs, dependent Windows Runtime assemblies must be resolved on demand through the ReflectionOnlyNamespaceResolve event."
If I try to ReflectionOnlyLoad the referenced assemblies, then I get the error:
"Could not load file or assembly 'Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)".
This is related to loading winmd references, and explained in the post here: Could not load file or assembly 'Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime'.
The full code I'm trying is this:
using System.Runtime.InteropServices.WindowsRuntime;
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
/*WindowsRuntimeMetadata.ReflectionOnlyNamespaceResolve += (x, y) =>
{
y.NamespaceName ???
y.ResolvedAssemblies.Add(Assembly.ReflectionOnlyLoadFrom(???));
return;
};*/
foreach (var references in assembly.GetReferencedAssemblies())
{
try
{
Assembly.ReflectionOnlyLoad(references.FullName);
}
catch (FileNotFoundException)
{
var fi = new FileInfo(assemblyPath);
var fi2Name = String.Format("{0}\\{1}.dll", fi.DirectoryName, references.Name);
var fi2 = new FileInfo(fi2Name);
if (fi2.Exists)
{
Assembly.ReflectionOnlyLoadFrom(fi2.FullName);
}
}
catch (FileLoadException)
{
// When a winmd assembly is attempted.
}
}
return assembly;
Any more ideas?
Thanks, Jon
Edit 2
The latest idea successfully resolves "{Windows.UI.Xaml, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime}".
However, when ".GetExportedTypes()" is called on the "Client.exe" assembly, the 'ReflectionOnlyNamespaceResolve' event is only fired once for namespace "Windows.UI.Xaml", which resolves to "C:\windows\system32\WinMetadata\Windows.UI.Xaml.winmd".
An exception is then thrown within ".GetExportedTypes()", which is "Cannot resolve dependency to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.".
If you want only to discover the containing types you should use the Assembly.ReflectionOnlyLoad method.
Assembly.ReflectionOnlyLoadFrom(#"c:\...\MyWinRTApp.exe")
UPDATE
Here's the code that works for me:
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (sender, eventArgs) => Assembly.ReflectionOnlyLoad(eventArgs.Name);
WindowsRuntimeMetadata.ReflectionOnlyNamespaceResolve += (sender, eventArgs) =>
{
string path =
WindowsRuntimeMetadata.ResolveNamespace(eventArgs.NamespaceName, Enumerable.Empty<string>())
.FirstOrDefault();
if (path == null) return;
eventArgs.ResolvedAssemblies.Add(Assembly.ReflectionOnlyLoadFrom(path));
};
Assembly loadFrom = Assembly.ReflectionOnlyLoadFrom(#"C:\....\WinRTApp.exe");
Type[] types = loadFrom.GetExportedTypes();
foreach (Type type in types)
{
Console.WriteLine(type);
}

GetType(string) returns null after AppDomain.CurrentDomain.Load

I'am building a small plugin architecture (unfortunately MEF is not an options because it needs to run on .NET 2.0).
I want to be able to put dll's in a directory without recompiling the main project.
My main project is a winforms application which has some dialogs to pick an implementation of an interface the main program needs.
I have a method that searches a certain directory and gives a List of locations of the dll's I want to search for Types that implement the interface.
public List<Type> GetPluginTypes()
{
List<Type> types = new List<Type>();
foreach (string dll in this.Plugins)
{
Assembly assembly;
try
{
assembly = AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(dll));
}
catch
{
continue;
}
foreach (Type type in assembly.GetExportedTypes())
{
if (type.IsInterface || type.IsAbstract)
continue;
if (typeof(IMyInterface).IsAssignableFrom(type))
types.Add(type);
}
}
return types;
}
Using this method I show the user a list of implementations, one is chosen and it's AssemblyQualifiedName is saved to a settings file.
When I start the main application, I load the AQN from the settings and load all the plugins into the AppDomain by calling the above method.
string typeName = GetSetting("MyPlugin");
GetPluginTypes(); // just to load the plugins into the app domain
Type.GetType(typeName); // allways returns null.
Here is my problem: Type.GetType(typeName), always returns null.
I used Type.GetType(typeName, true), to enforce an exception, which I got:
Could not load file or assembly 'MyImpl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.":"MyImpl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}
I am clueless. I've already loaded the assembly into the AppDomain, and still Type.GetType(string) can't find it when I specify the AQN.
This can be solved by registering the AppDomain.AssemblyResolve event for the AppDomain which will request the assembly and make the handler return the already loaded assembly.
Here is what the handler looks like in C#:
private System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
return
AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(Kandidaat => string.Equals(Kandidaat.GetName().FullName, args.Name));
}
a detailed explanation can be found here:
https://msdn.microsoft.com/en-us//library/ff527268(v=vs.110).aspx
appdomain assemblyresolve
Perhaps this is relevant. From the documentation for Type.GetType(String, Boolean):
If typeName includes only the name of
the Type, this method searches in the
calling object's assembly, then in the
mscorlib.dll assembly. If typeName is
fully qualified with the partial or
complete assembly name, this method
searches in the specified assembly.
You said that you try calling with type.AssemblyQualifiedName, but it failed. Did you check the qualified name to see if it was reasonable?

Categories