I seem to be having the same problems. I can load assemblies all day in the current AppDomain without references and without interfaces if need be. But try as I may they will ot unload. I have been working on this problem for weeks. I have seen other apps using Remoting but I know there has got to be a way to create a child AppDomain and reference obkect via reflection and uload the child domain when finished.
My Scenario. I have windows services which are basically libraries called obviously by a service wrapper. Since the wrapper does the instansiation, I want to update these dlls without stopping and restarting my service.
I have created a mockup using a form and a separate dll
Here is the mockup simple dll the form will call:
using System;
namespace TestClass
{
public class Test : MarshalByRefObject
{
public string GetResponse()
{
return "Test Response 1";
}
}
}
Here is the form code:
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Reflection;
namespace DomainTest
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnLoad;
private System.Windows.Forms.Button btnUnload;
private System.Windows.Forms.Button btnCall;
private System.Windows.Forms.TextBox txtResponse;
private AppDomain _runDomain;
private Assembly _assembly;
private Type _typTest;
Object _objTest;
AppDomainSetup _appSetup;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
_appSetup = new AppDomainSetup();
_appSetup.ApplicationBase = @"E:\Development\.Net\CSharp\Examples\AppDomain\AppDomainEnvironment";
_runDomain = AppDomain.CreateDomain("MyDomain", null, _appSetup);
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnLoad = new System.Windows.Forms.Button();
this.btnUnload = new System.Windows.Forms.Button();
this.btnCall = new System.Windows.Forms.Button();
this.txtResponse = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// btnLoad
//
this.btnLoad.Location = new System.Drawing.Point(30, 35);
this.btnLoad.Name = "btnLoad";
this.btnLoad.Size = new System.Drawing.Size(70, 25);
this.btnLoad.TabIndex = 0;
this.btnLoad.Text = "Load";
this.btnLoad.Click += new System.EventHandler(this.btnLoad_Click);
//
// btnUnload
//
this.btnUnload.Enabled = false;
this.btnUnload.Location = new System.Drawing.Point(300, 35);
this.btnUnload.Name = "btnUnload";
this.btnUnload.Size = new System.Drawing.Size(70, 25);
this.btnUnload.TabIndex = 1;
this.btnUnload.Text = "Unload";
this.btnUnload.Click += new System.EventHandler(this.btnUnload_Click);
//
// btnCall
//
this.btnCall.Enabled = false;
this.btnCall.Location = new System.Drawing.Point(166, 35);
this.btnCall.Name = "btnCall";
this.btnCall.Size = new System.Drawing.Size(70, 25);
this.btnCall.TabIndex = 2;
this.btnCall.Text = "Call";
this.btnCall.Click += new System.EventHandler(this.btnCall_Click);
//
// txtResponse
//
this.txtResponse.Location = new System.Drawing.Point(30, 85);
this.txtResponse.Name = "txtResponse";
this.txtResponse.Size = new System.Drawing.Size(340, 20);
this.txtResponse.TabIndex = 3;
this.txtResponse.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(402, 441);
this.Controls.Add(this.txtResponse);
this.Controls.Add(this.btnCall);
this.Controls.Add(this.btnUnload);
this.Controls.Add(this.btnLoad);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
[sTAThread]
static void Main()
{
Application.Run(new Form1());
}
private void btnLoad_Click(object sender, System.EventArgs e)
{
_assembly = AppDomain.CurrentDomain.Load("TestClass");
_typTest = _assembly.GetType("TestClass.Test");
_objTest = _runDomain.CreateInstance("TestClass", "TestClass.Test");
System.Diagnostics.Debug.WriteLine(_objTest.GetType());
btnCall.Enabled = _objTest != null;
btnUnload.Enabled = _objTest != null;
btnLoad.Enabled = _objTest == null;
}
private void btnCall_Click(object sender, System.EventArgs e)
{
MethodInfo method = _typTest.GetMethod("GetResponse");
txtResponse.Text = (string) method.Invoke(_objTest, null);
}
private void btnUnload_Click(object sender, System.EventArgs e)
{
AppDomain.Unload(_runDomain);
btnCall.Enabled = false;
btnLoad.Enabled = true;
btnUnload.Enabled = false;
}
}
}
The Results:
The issue is that when calligna method off of the newly created object I get the following error:
Object does not match target type.
I looked at the actual object type from the object created with this line of code:
_objTest = _runDomain.CreateInstance("TestClass", "TestClass.Test");
The object is not a TestClass.Test Type object, it is a System.Runtime.Remoting.ObjectHandle type object.
Soooooooooooooooooooo....
How to get around this? Am I even close here?