How to redirect a method call? - c#

I have got a DLL which works fine in Windows, but Inside one of its private functions the static System.IO.File.ReadAllBytes() is called. I have to use this DLL on a windows CE smart Device Project with Compact Framework 3.5 and there is no such method in the System.IO.File. I have tried to create a class named "File" inside the project like this:
public class File
{
internal static byte[] ReadAllBytes(string path)
{
}
internal static void WriteAllBytes(string path, byte[] bytes)
{
}
}
My own calls to the static Methods of the class File are redirected here But the calls inside the DLL methods still go to the System.Io.File class and I still get the MissingMethodException. I tried the methods with public modifiers but saw no change.
I even tried to rewrite the public method that calls the private method inside which the ReadAllbytes was invoked and used MethodInfo.Invoke with no success.
The question: Is there a way to force the method inside the Dll to accept my ReadAllbytes Method instead of System.File.IO.ReadAllBytes()? The invocation inside the DLL is like this:
using System.IO.File;
namespace Something
{
class SomeClass
{
public Boolean someMethod()
{
byte[] myBytes = File.ReadAllBytes(filePath);
}
}
}

Static methods like File.ReadAllBytes are resolved at compile time to a specific Assembly name and class. You will need to modify the DLL to change the call. Prehaps you could decompile and recompile it, or edit the IL.
*It is possible to redirect the call using the profiling hooks (the sameone the debugger uses), and that is how the Moles Mocking framework works. However it would not be suitable for production use.

Related

Python for .Net and C# extensions - SignalR client in Python (On method not working)

I'm trying to access Microsoft.SignalR library from Python for .Net in Visual Studio, and some of the implementation of a Hub (IHubProxy) is in an extension: HubProxyExtensions
Python for .Net does not seem to cover extensions in the readme, and I can't find any reference (my google fu is not working in this case.)
I'm able to load the extensions class directly, but calling the method fails:
ext = SignalR.Client.HubProxyExtensions
ext.On(self._proxy, method, handle)
The extension class loads and reports as a meta class and has methods from the immediate window
ext
<CLR Metatype>
dir(ext)
['Equals', 'Finalize', 'GetHashCode', 'GetType', 'GetValue', MemberwiseClone', 'Observe', 'On', 'Overloads', 'ReferenceEquals', 'ToString', __call__', '__class__', '__cmp__', ...]
Calling ext.On() crashes the process.
Does Python for .Net support extensions at all? (Or is it just a problem specific to this particular implementation)
Update: Doing a simple test on extensions, it looks like Python for .Net does handle extensions properly, so there is something wrong with my call to Signalr specifically... more testing to come.
So I'm going to answer my own question since it turned out to be multiple issues; and I didn't see others addressing this directly.
Action templates:
The problem in my case is there is no way to bind Action templates in Python for .Net. So there is no way to call the correct On methods in a hub.
Someone else found the same issue recently
Extensions:
Python for .Net can call extension methods; Simply call the static extension method through the extension class like any other static class methods.
C#
namespace ExtensionTest
{
public class MyClass
{
public string MyMethod(string something)
{
System.Console.Out.WriteLine(string.Format("Hi! This is something! {0}", something));
return something + " something else";
}
}
}
namespace ExtensionTest
{
public static class MyExtension
{
public static string MyExtensionMethod(this MyClass myclass, string something)
{
System.Console.Out.WriteLine(string.Format("This is the extension {0}", something));
string somethingelse = myclass.MyMethod(something);
return somethingelse + " more of something";
}
}
}
Python:
import clr
clr.AddReference('ExtensionTest')
import ExtensionTest
obj = ExtensionTest.MyClass()
s = obj.MyMethod('Hi')
print s
s = ExtensionTest.MyExtension.MyExtensionMethod(obj, 'Hello!')
Output:
Hi! This is something! Hi
Hi something else
This is the extension Hello!
Hi! This is something! Hello!
Hello! something else more of something
I'm not sure why this isn't mentioned on the readme for python for .net.
I guess it's obvious :)

C#, Context Object with Method that takes Interface to External DLL, Throws MissingMethodException

I have a service which acts as a scripting engine for normalization of content. The service extends its scripting language by dynamically loading DLLs at startup, passing a context object interface to a Load() method in each DLL. The context object provides the DLL with methods for Binding string names to factory objects, commands/functors, script object wrappers, etc.
I am having a problem where when the Load() method of one of the DLLs is called it throws a MissingMethodException if it attempts to call one of the binding methods. The method is one which takes an interface which is declared in another DLL, and I suspect something is going on with the method signature when passing the context object through Type.GetMethod.Invoke().
It should be noted that the exception is only thrown when dynamically loading the DLL via Assembly.LoadFile(). Referencing the DLL in the main process and using reflection to get the class/method, then dynamically invoking it from there causes no exception to be thrown.
My code/project reference setup ...
Content.dll:
References nothing
public class ContentPackage { ... }
public interface IContentDataSource
{
ContentPackage Receive();
void Send(ContentPackage content);
}
public interface IContentDataSourceFactory
{
IContentDataSource CreateInstance(string param);
IEnumerable<IContentDataSource> CreateInstances(string param);
}
public class ContentXmlDataSource : IContentDataSource
{
ContentPackage IContentDataSource.Receive() { ... }
void IContentDataSource.Send(ContentPackage content) { ... }
public class Factory : IContentDataSourceFactory
{
IContentDataSource IContentDataSourceFactory.CreateInstance(string param) { return new ContentXmlDataSource(param); }
IEnumerable<IContentDataSource> IContentDataSourceFactory.CreateInstances(string param) { ... }
IContentDataSourceFactory.CreateInstance(
public static Factory Singleton { get { return s_Singleton; } }
private static Factory m_Singleton = new Factory();
}
}
ExtensionInterface.dll:
References Content.dll
public interface IXmlTagCommand() { ... }
public interface IExtensionBindingContext
{
void BindCommand(string name, IXmlTagCommand cmd);
void BindDataSourceFactory(string name, IContentDataSourceFactory factory);
}
Service.dll:
References ExtensionInterface.dll, Content.dll
public partial class TheService
{
public class ExtensionBindingContext : IExtensionBindingContext
{
void IExtensionBindingContext.BindCommand(string name, IXmlTagCommand cmd)
{ ... }
void BindDataSourceFactory(string name, IContentDataSourceFactory factory)
{ ... }
ExtensionBindingContext(string basePath)
{
var paths = Directory.GetFiles(basePath, "*.dll");
foreach (var path in paths)
{
Assembly assembly = Assembly.LoadFile(path);
Type t = assembly.GetType("ExtensionLibrary");
MethodInfo method = t.GetMethod("Load",
BindingFlags.Public | BindingFlags.Static);
method.Invoke(null, new object[] { this }); // Throws exception!
}
}
}
TheService()
{
(new ExtensionBindingContext()).LoadExtensions(".\DLLFolder\");
}
}
Extension.StandardContentFactories.dll: (Loaded dynamically)
References ExtensionInterface.dll, Content.dll
public class ExtensionLibrary
{
public void Load(IExtensionBindingContext context)
{
context.BindCommand("SomeCommand", XTagCommands.SomeCommand); // Fine: No exception.
context.BindDataSourceFactory("ContentXml", ContentXmlFactory.Singleton); // Causes whole function to throw exception if not commented out, preventing even the "BindCommand" call to not be reached.
}
}
The exception specifics:
Exception:
System.Reflection.TargetInvocationException, {"Exception has been thrown by the target of an invocation."}
Inner Exception:
{"Method not found: 'Void SomeNamespace.ContentService.IExtensionBindingContext.BindDataSourceFactory(System.String, SomeNamespace.Content.IContentDataSourceFactory)'."}
If I comment out the BindDataSourceFactory() line in StandardContentFactories.dll, the problem goes away. I am also successfully loading multiple other DLLs in this manner.
I've tried the following:
- Checking GAC folders for same named assemblies from project, none found
- Cleaning solution and rebuilding
- Verifying that all assemblies were using same .NET (4.0, not client profile)
- Passing the interface in a wrapper object instead, changing the method to take the wrapper: Field not found exception instead
- Passing the factory object as an "Object" (updating method parameters as well), then casting that object back into the interface that the factory object inherits: Invalid cast
Is there some kind of issue with passing objects behind interfaces to DLLs via dynamic assembly loading and invoking if that interface has a method that takes an interface which is defined in another referenced assembly? Are there possible work arounds to allow for this dynamic binding of factories from unknown DLLs if the interface issue is non-solvable?
EDIT:
After checking the modules as per mike z's suggestion, I see that their are two copies of each shared interface DLL being loaded (Content.dll and ExtensionInterface.dll); the first set of DLLs is being loaded from the service's host process bin\Debug directory; the second set of DLLs is being loaded from the bin\Debug directory of the first addon DLL that is loaded by Assembly.LoadFile().
The process uses an array of directory paths to search for addon DLLs in, and I was able to force the process to find/load the DLL that has the problem first, which caused the problem to go away. I'm guessing that all of the Assembly.LoadFile() loaded DLLs are using the set of shared interface DLLs that are loaded as a side effect of the first call to Assembly.LoadFile() (i.e. for the first addon DLL). When these DLLs load, maybe they are only including interface information for the IExtensionBindingContext.BindCommand() but not the IExtensionBindingContext.BindDataSourceFactory() and/or IContentDataSourceFactory since they are not used by that DLL.
Does anybody know if this assessment is correct? If so, is there a (standard or correct) way to force my Assembly.LoadFile() DLLs to correctly load ALL of the interface/method information from a shared library? (I'd rather not use contrived solutions like forcing the load order from a config file or creating a fake library that used all the features at the start.)

PowerShell: how does the PowerShell instantiate C# classes

Initially, I think PowerShell instantiate one class only when the cmdlet tagged on this class is called. On execution, each cmdlet falls into the BeginProcess -> ProcessRecord -> EndProcess(StopProcess) path, and after the EndProcess is done, it seems the process will end and then the memory will collect all these class objects as garbage.Therefore each class should live in their own life cycle and not share any resources. When we are calling these cmdlets,
However I find that classes do share the same static values in the same module. For example, assume in my project I have two classes:
namespace PSDSL
{
[Cmdlet(VerbsCommon.Get, "MyTest")]
public class GetMyTest : Cmdlet
{
public static GlobalUserName = "";
[Parameter(Mandatory = false)]
public string Filepath { get; set; }
protected override void InnerProcessRecord()
{
if (_filepath != null)
{
GlobalUserName = _filepath;
}
Console.WriteLine(GlobalUserName);
}
}
}
namespace PSDSL
{
[Cmdlet(VerbsCommon.Get, "MyTest2")]
public class GetMyTest2 : Cmdlet
{
[Parameter(Mandatory = false)]
public string Filepath { get; set; }
protected override void InnerProcessRecord()
{
if (_filepath != null)
{
GlobalUserName = _filepath;
}
Console.WriteLine(GlobalUserName);
}
}
}
The two commands are pretty similar except one defines a static GlobalUserName. Calling these 2 cmdlets shows that the GlobalUserName can be read\write from both cmdlets.
My confusion is that, when are the classes be instaniated?
Whole assembly loaded at once and stays loaded till restart of the PowerShell prompt.
Details:
Smallest unit of code isolation in .Net is Assembly (in most cases single managed DLL).
Process that uses managed runtime can't load less than single assembly at a time - so all classes from that assembly (and related once on demand) will be loaded together. As result all static fields will be present at the same time in memory (note that static fields are initialized "before first use of the class" which mean they are not necessary initialized on load of the assembly).
There also no way to "unload" class or even assembly without using separate AppDomains. PowerShell does not use multiple AppDomains to load assemblies for different modules (generally cross-AddDomain calls require special attention during implementation and you'd know about it by now). As result once loaded module stays in memory till you quit PowerShell (covered in Powershell Unload Module... completely).
Since assembly is loaded once for all commandlets in it all static fields will be present at once and keep they values till exiting of PowerShell.
Side note: I'd strongly recommend avoiding static fields for anything but really static immutable data in general. It is way to easy to leave some random values there and impact future code. In PowerShell pipeline is the way to pass information between commandlets, other types of processes (WinForms, ASP.Net,...) have they own preferred mechanism to pass data instead of using static.

Common "Debug" function within class library

I am using several class libraries within a project, and one of them is a typical "project.common.dll" library containing some common helper functions. One of these functions is a debug function that creates debug output.
Now I would like to enable/disable debug output by using a user-level property (application settings). How can I reference variables defined in main application's program.cs within this class library ?
Update : Thanks all. I will probably create a static method in my base application that performs the check (to debug or not) and then calls the Debug function in the common library.
You can't.
What you will need to do is have the properties in the class library itself and when you create the instance of it in your main application pass the user setting in:
var debug = new DebugInstance { Output = this.Output };
or set the parameters if it's a static class:
StaticDebug.Output = this.Output;
You can use the ConditionalAtrribute:
[Conditional("DEBUG")]
public static void WriteDebugInfo()
{
Trace.WriteLine("what ever...")
}
This way when you build in Debug mode, the method is invoked; in Release mode not.
Use parameters on the constructor of the Debug class (or a static constructor if the class is static).

Hooking into an "OnLoad" for class library

Does anyone know if there's a way to hook into an "OnLoad" event to run some operations when an assembly loads?
Specifically, I am creating a plug-in for an application. The plug-in's DLL gets loaded and objects start being used, but the problem is I need to load another assembly dynamically before anything happens. This assembly can't be copied to the application's directory and must remain invisible to it.
You need to hook on to AssemblyLoad event.
Refer-
http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyload.aspx
It is really sad that writing a Main() function in an Assembly DLL is never called by the .NET framework.
It seems that Microsoft forgot that.
But you can easily implement it on your own:
In the DLL assembly you add this code:
using System.Windows.Forms;
public class Program
{
public static void Main()
{
MessageBox.Show("Initializing");
}
}
Then in the Exe Assembly that loads this DLL you add this function:
using System.Reflection;
void InitializeAssembly(Assembly i_Assembly)
{
Type t_Class = i_Assembly.GetType("Program");
if (t_Class == null)
return; // class Program not implemented
MethodInfo i_Main = t_Class.GetMethod("Main");
if (i_Main == null)
return; // function Main() not implemented
try
{
i_Main.Invoke(null, null);
}
catch (Exception Ex)
{
throw new Exception("Program.Main() threw exception in\n"
+ i_Assembly.Location, Ex);
}
}
Obviously you should call this function at the very beginning before doing anything else with that Assembly.
C# does not provide a way to do that but the underlying IL code does via module initializers. You can use tools like Fody/ModuleInit to turn a specially named static C# class to run as a module initializer which will be run when your dll is loaded.

Categories