how to call a method of a class from another appDomain - c#

my application want to call a method of a class that is from another AppDomain.
AppDomain env = AppDomain.CreateDomain(
"test",
null,
new AppDomainSetup() { ApplicationName = "test" }
);
Assembly a = Assembly.LoadFrom("d:\\testenv1\\test2.dll");
//env.AssemblyResolve += new ResolveEventHandler(env_AssemblyResolve);
env.Load(a.FullName);
ObjectHandle o = env.CreateInstance(a.FullName, "Test2.Class1");
now i have the object handle of the Test2.Class1, but i have no idea how to invode the "action" method of the Class1 class.
the "action" method likes this:
public void action()
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + " ok");
}
i tried to use o.unwrap() method to get the reference of the object, but it seems the object has been transferred into the current domain, so the output of the "action" method prints the current domain name.

Mark the object that you want to use for cross appdomain communication as MarshalByRefObject.

Related

C# How can I identify the method that created the thread the current method is in?

I'm looking to identify the method that created the Thread that the current method is running in.
I would use new StackFrame(int).GetMethod().Name, but I'm in a new Thread at the time of running this, so this one is out.
An example of my code is below:
private void doSomething(object sender, EventArgs e)
{
try
{
Thread thread = new Thread(new ParameterizedThreadStart(GenerateThreadMethod));
thread.Start(new Dictionary<String, Object>() {
{ "date" , Convert.ToDateTime(monthCalendar.SelectionRange.Start)},
{ "path", myList[myListBox.SelectedIndex][1] }
});
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void GenerateThreadMethod(Object obj)
{
Dictionary<String, Object> data = (Dictionary<String, Object>)obj;
DateTime date = (DateTime)data["date"];
String path = (String)data["path"];
//I want to find the name of doSomething() right here
doMoreThings(date, path);
}
There's no built in way to do this. However you can pass an arbitrary object to your ParametrizedThreadStart delegate which can include whatever information you want to communicate including the calling method name.
You can't identify the parent thread.
I've seen another suggest that you could try prefix the name of the new thread with the thread ID from the parent thread, and then create a constructor on the method you want to spawn that requires the thread ID from the parent.
You could then use this information to at least gain access to the parent thread, and go from there, but I'm not sure if that gets you close enough to what you were hoping to achieve.
I don't think there is a way to access it as your new thread has it's own context. I would rather suggest to pass the name of the caller when creating the thread.
So in the caller you would write
StackTrace st = new StackTrace ();
StackFrame sf = st.GetFrame (0);
MethodBase currentMethodName = sf.GetMethod ();
And pass the result to your new thread as parameter of the call.

Attaching a debugger to code running in another app domain programmatically

I am working on a Visual Studio extension and one of it's functions creates a new app domain and load an assembly into that app domain. Then it runs some functions in the app domain. What I'd like to do, and am not sure if it's possible, is have my extension attach a debugger to the code running in the new app domain so when that code fails, I can actually see what's going on. Right now I'm flying blind and debugging the dynamical loaded assembly is a pain.
So I have a class that creates my app domain something like this:
domain = AppDomain.CreateDomain("Test_AppDomain",
AppDomain.CurrentDomain.Evidence,
AppDomain.CurrentDomain.SetupInformation);
And then creates an object like this:
myCollection = domain.CreateInstanceAndUnwrap(
typeof(MyCollection).Assembly.FullName,
typeof(MyCollection).FullName,
false,
BindingFlags.Default,
null,
new object[] { assemblyPath }, null, null);
MyCollection does something like this in it's constructor:
_assembly = Assembly.LoadFrom(assemblyPath);
So now that assembly has been loaded into Test_AppDomain since the MyCollection object was created in that domain. And it's that loaded assembly that I need to be able to attach the debugger to.
At some point myCollection creates an instance of an object and hooks up some events:
currentObject = Activator.CreateInstance(objectType) as IObjectBase;
proxy.RunRequested += (o, e) => { currentObject?.Run(); };
And basically where I have the handler for RunRequested and it runs currentObject?.Run(), I want to have a debugger attached, although it probably wouldn't be a problem (and may actually work better) if the debugger was attached earlier.
So is there a way to achieve this? Is it possible to programmatically attach a debugger when the user triggers the event that will lead to the Run function of the object created in the new AppDomain being called? How do I get the debugger attached to that (and not the extension itself)?
I tried something like this:
var processes = dte.Debugger.LocalProcesses.Cast<EnvDTE.Process>();
var currentProcess = System.Diagnostics.Process.GetCurrentProcess().Id;
var process = processes.FirstOrDefault(p => p.ProcessID == currentProcess);
process?.Attach();
But it seems the id from System.Diagnostics.Process.GetCurrentProcess().Id doesn't exist within LocalProcesses?
Even though you likely have already moved on, I found the problem very fascinating (and related to what I've been researching to blog about). So I gave it a shot as an experiment - I wasn't sure how you intended to trigger the Run() method with events (and even if it was material for your use case) so I opted for a simple method call.
Injecting Debugger.Launch()
as a PoC I ended up IL-emitting a derived class and injecting a debugger launch call before passing it onto dynamically loaded method:
public static object CreateWrapper(Type ServiceType, MethodInfo baseMethod)
{
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName($"newAssembly_{Guid.NewGuid()}"), AssemblyBuilderAccess.Run);
var module = asmBuilder.DefineDynamicModule($"DynamicAssembly_{Guid.NewGuid()}");
var typeBuilder = module.DefineType($"DynamicType_{Guid.NewGuid()}", TypeAttributes.Public, ServiceType);
var methodBuilder = typeBuilder.DefineMethod("Run", MethodAttributes.Public | MethodAttributes.NewSlot);
var ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.EmitCall(OpCodes.Call, typeof(Debugger).GetMethod("Launch", BindingFlags.Static | BindingFlags.Public), null);
ilGenerator.Emit(OpCodes.Pop);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.EmitCall(OpCodes.Call, baseMethod, null);
ilGenerator.Emit(OpCodes.Ret);
/*
* the generated method would be roughly equivalent to:
* new void Run()
* {
* Debugger.Launch();
* base.Run();
* }
*/
var wrapperType = typeBuilder.CreateType();
return Activator.CreateInstance(wrapperType);
}
Triggering the method
Creating a wrapper for loaded method seems to be as easy as defining a dynamic type and picking a correct method from target class:
var wrappedInstance = DebuggerWrapperGenerator.CreateWrapper(ServiceType, ServiceType.GetMethod("Run"));
wrappedInstance.GetType().GetMethod("Run")?.Invoke(wrappedInstance, null);
Moving on to AppDomain
The above bits of code don't seem to care much for where the code will run, but when experimenting I discovered that I'm able to ensure the code is in correct AppDomain by either leveraging .DoCallBack() or making sure that my Launcher helper is created with .CreateInstanceAndUnwrap():
public class Program
{
const string PathToDll = #"..\..\..\ClassLibrary1\bin\Debug\ClassLibrary1.dll";
static void Main(string[] args)
{
var appDomain = AppDomain.CreateDomain("AppDomainInMain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
appDomain.DoCallBack(() =>
{
var launcher = new Launcher(PathToDll);
launcher.Run();
});
}
}
public class Program
{
const string PathToDll = #"..\..\..\ClassLibrary1\bin\Debug\ClassLibrary1.dll";
static void Main(string[] args)
{
Launcher.RunInNewAppDomain(PathToDll);
}
}
public class Launcher : MarshalByRefObject
{
private Type ServiceType { get; }
public Launcher(string pathToDll)
{
var assembly = Assembly.LoadFrom(pathToDll);
ServiceType = assembly.GetTypes().SingleOrDefault(t => t.Name == "Class1");
}
public void Run()
{
var wrappedInstance = DebuggerWrapperGenerator.CreateWrapper(ServiceType, ServiceType.GetMethod("Run"));
wrappedInstance.GetType().GetMethod("Run")?.Invoke(wrappedInstance, null);
}
public static void RunInNewAppDomain(string pathToDll)
{
var appDomain = AppDomain.CreateDomain("AppDomainInLauncher", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
var launcher = appDomain.CreateInstanceAndUnwrap(typeof(Launcher).Assembly.FullName, typeof(Launcher).FullName, false, BindingFlags.Public|BindingFlags.Instance,
null, new object[] { pathToDll }, CultureInfo.CurrentCulture, null);
(launcher as Launcher)?.Run();
}
}
One way to get around this is to generate another assembly with a function that will take in a MethodInfo object and simply call System.Diagnostics.Debugger.Launch() and then the given MethodInfo, and then all you have to do is unwrap that assembly's function call it with whatever Method's Info you want to start the actual domain in, and your good it will enable the debugger and then call the method you want it to start in.

How to test new Object within a function using RhinoMocks and mbunit

I am trying to test the below method using RhinoMocks and MbUnit however I am unable to get the test to pass. The current error is when the expect call for "" is not found.
The function is in vb.net and the test is in c#
Public Function Login(user As Website.BusinessObjects.User) As Integer Implements IActivityLog.Login
Dim item As BOAudit.IActivityLog = New BOAudit.ActivityLog(_request)
' Activity
item.UserID = User.GuidID
item.Type = Enums.ActivityType.Login
item.Description = String.Format(If(IsAdmin, "Logged in as {0}", "Logged in"), User.FullName)
item.EventUserID = _authenticatedUser.GuidID
Return _dalActivityLog.Save(item)
End Function
The test below is what I currently have and I believe the issue is down to declaring a new object within the function above and not passing that object into the function. What is the best way to test the above function and should I be passing in the object?
[Test]
public void Login_Data_NewRecordCreated()
{
const int id = 99;
var data = new Website.CodeModules.BusinessObjects.Audit.ActivityLog(_request)
{
Type = Enums.ActivityType.Login,
Description = "Logged in",
EventUserID = _user.GuidID
};
var user = _mocks.StrictMock<User>();
using (_mocks.Record())
{
Expect.Call(_dalActivityLog.Save(data)).Return(id);
}
using (_mocks.Playback())
{
var result = _balActivityLog.Login(user);
Assert.AreEqual(id, result);
}
}
The condition you assert in your test does not seem to have much sense. Your code seems to test that the mock instance in _dalActivityLog returns the constant that you've set up.
In that test you should test the code of the function Login, not the _dalActivityLog implementation. Thus, you should check that _dalActivityLog.Save is called with the right parameter passed.
I suppose that _dalActivityLog is an instance of a class that implements an interface that you haven't specified in your question. Let's call it IActivityLog. Then you should set up a mock instance of it in your test code.
IActivityLog logMock = MockRepository.GenerateStub<IActivityLog>();
Then you inject somehow this mock instance into the instance of the class the has the Login method (via constructor or property).
Then call your Login method and pass there an instance of User.
Then you make the assertion about the _dalActivityLog.Save call, like the one below.
logMock.AssertWasCalled(
call => call.Save(
Arg<Website.CodeModules.BusinessObjects.Audit.ActivityLog>.Matches(
logItem => logItem.UserID == user.GuidID && logItem.Type == Enums.ActivityType.Login
)
)
);

get assembly of method

Imagine the following situation:
Assembly A is starting the program. (it has a main method)
it loads Assembly B via reflection and instantiates a class of Assembly B.
in this instance a method is called where i would like to get to the Assembly B.
i have already tried
System.Reflection.Assembly.GetCallingAssembly();
System.Reflection.Assembly.GetExecutingAssembly();
but they always give me Assembly A instead of B.
Try getting type of class contain the method you are going for and get its assembly.
string assemblyName = this.GetType().Assembly.FullName;
The Assembly.GetExecutingAssembly() is the proper method to use.
You leave preciously few breadcrumbs to diagnose the cause of having trouble with it. There are however strings attached to this. An important job performed by the jitter is to make methods disappear. This is an optimization called "inlining". In effect, the call to the method is replaced by the code of the method. It is a very important optimization, it for example makes properties as cheap as using public fields. But a consequence it that you'll get the assembly of the calling method. In your case Main(). So you'll see assembly A and not B.
This is not something you ought to tinker with, avoid having a need for this. A method shouldn't be puzzled about what assembly it lives in, you could for example use the typeof(T).Assembly property where T is the class in which the method lives.
You can disable the inlining optimization, you do so with an attribute:
using System.Runtime.CompilerServices;
...
[MethodImpl(MethodImplOptions.NoInlining)]
public void Foo() { }
try this sample ,
public static object ExecuteAssemblyMethod(string methodName,Type assemblyObj, object[] arguments)
{
object result = null;
try
{
object ibaseObject = Activator.CreateInstance(assemblyObj);
result = assemblyObj.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, ibaseObject, arguments);
}
catch (ReflectionTypeLoadException emx)
{
result = null;
return result;
}
catch (Exception ex)
{
result = null;
return result;
}
return result;
}
Usage:-
Assembly assemb = Assembly.LoadFile(#"D:\TEMP\TestClassLibrary_new.dll");
Type testType = assemb.GetType("TestClassLibrary.Class1");
object[] param = new object[] {"akshay" };
object result = LoadAssembly.ExecuteAssemblyMethod("GetName", testType, param);

Delegate in method using variables in scope of method but outside delegate scope

I wrote some sample code where I have an Action delegate declared in a method body where two params are passed and then consumed by the delegate code without those params being passed into the delagte. It seems cleaner to me to explictely pass in these params to the delegate too, but in this case I am not, and this code would work fine.
I am wondering how .NET keeps these references available in the export delegate that is now running on a new thread.
public void MyMethod(string name, ComplexObject myObj)
{
Action export = () => {
//do something with name
name = name + name;
//do something with complex reference object
myObj.SomeMethod(name);
};
// do more work
// example launch export on a new thread
System.Threading.Thread newThread = new System.Threading.Thread(new System.Threading.ThreadStart(export));
newThread.Start();
}
The compiler creates a special type that keeps those variables. Then, instead of storing those variables on the stack, it instantiates an instance of that type every time you call that method. Then, the anonymous delegates use a reference to that new instance to get access to those variables.

Categories

Resources