Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

NETMF 4.0 Appdomain loading assemblies

61 views
Skip to first unread message

oenren

unread,
Nov 24, 2009, 3:46:02 AM11/24/09
to
During developing a plugin interface based on MF 4.0 I recognized some
strange behaviour with the AppDomain functionality of the Micro Framework.

My goal is creating a plugin interface based on the Micro Framework 4.0
which is using several AppDomains for loading/creating instances of different
asemblies.

Q1.
When using the AppDomain.CurrentDomain it's possible to load a assembly and
it's possible to create a instance of a type available in a assembly. This
functionality is only working for assemblies which I added to my project
references, is there a way to get this functionality working for assemblies I
didn't add to my project references?

Q2.
My second question is about creating new appdomains and use these newly
created appdomains for loading asemblies in it. After creating a new
AppDomain it's not possible to load a assembly in this appdomain or create a
instance of a type within a assembly inside this appdomain. I get a
ArgumentNullException, I guess the assembly I tried to load is not available
in the newly created appdomain, because this functionality is working well
when I use the AppDomain.CurrentDomain.
Am I missing something here?

Lorenzo Tessiore

unread,
Nov 24, 2009, 2:35:02 PM11/24/09
to
Q1. To create a type you need to load the asembly first into the type
system, and then load the assebly into the AppDomain. You can do the forst
operation by using the method Assembly.Load(byte[]). The byte[] will be the
actual assembly. E.g. you can load the assembly from the file system if you
have one.

Q2. After you create a new AppDomain, and before creating a type in that
AppDomain, you need to load the closure of the dependencies for the type you
want to create into the AppDomain. You can do this by using the method
AppDomain.Load(string assemblyName ). If you loaded the assembly first in
the type system (see Q1) then you will be able to load the assembly into your
new AppDomain. Once you have done that, then you can create a type using the
method AppDomain.CreateInstanceAndUnwrap(String assemblyName, String typeName)

here is a sample program to load known assemblies (use Assebly.Load first if
they are not known) into an AppDomain

using System;
using Microsoft.SPOT;

//--//

namespace DynamicLoading
{
public class Program
{
/// <summary>
/// The interface for a standlone application
/// </summary>
interface IApplication
{
/// <summary>
/// A sample method to invoke
/// </summary>
/// <returns></returns>
bool StartExecution();
/// <summary>
/// A sample method to transfer data
/// </summary>
/// <param name="c">A serializable class that can be trasferred
across applicaiton doamins</param>
/// <returns>A proxy to the instance of c in thsi
AppDomain</returns>
ClassToMarshal MarshalClass(ClassToMarshal c);
}

/// <summary>
/// A serializable class that can be trasferred across applicaiton
domains
/// </summary>
[Serializable]
public class ClassToMarshal
{
public int m_int;
public string m_string;

public ClassToMarshal(int i, string s)
{
m_int = i;
m_string = s;
}

public override bool Equals(object obj)
{
ClassToMarshal cls = obj as ClassToMarshal;

if (cls == null) return false;
if (cls.m_int != m_int) return false;
if (cls.m_string != m_string) return false;

return true;
}

public override int GetHashCode()
{
return base.GetHashCode();
}
}

/// <summary>
/// A class that can be loaded across applicaiton domains which
/// implements the IApplicaiton interface
/// </summary>
public class Application : MarshalByRefObject, IApplication
{
/// <summary>
/// we need a defautl consturctor to create an instance of this
object
/// across an application domain
/// </summary>
public Application()
{
}

/// <summary>
/// Implementation of the corresponding IApplication method
/// </summary>
/// <returns>Always true</returns>
bool IApplication.StartExecution()
{
return true;
}

/// <summary>
/// Implementation of the corresponding IApplication method
/// </summary>
/// <returns>A proxy to the instance of c in thsi
AppDomain</returns>
ClassToMarshal IApplication.MarshalClass(ClassToMarshal c)
{
return c;
}
}

/// <summary>
/// This methods compares two object instances for equivalence (same
memmbers all have same values)
/// and equality (the two objects are actually the same
/// </summary>
/// <param name="obj1">object to compare <paramref
name="obj2"/></param>
/// <param name="obj2">object to compare to <paramref
name="obj1"/></param>
/// <returns>true if objects are equivalent but not the same, false
otherwise</returns>
private static bool EqualsButNotSameInstance(object obj1, object obj2)
{
bool bResult = true;
if (!Object.Equals(obj1, obj2))
{
Debug.Print("ERROR: Object.Equals(obj1, obj2) returned
false");
bResult = false;
}
else if (Object.ReferenceEquals(obj1, obj2))
{
Debug.Print("ERROR : Object.ReferenceEquals(obj1, obj2)
returned true");
bResult = false;
}

return bResult;
}
/// <summary>
/// Creates a new Applicaiton domain, and then invoke codes and
transfer data from a IApplicaiton object
/// </summary>
/// <param name="appName">the AppDomain name</param>
/// <param name="entryPointAssm">The assembly that contains the
IApplication type</param>
/// <param name="assemblies">Allteh other assemblies needed</param>
/// <param name="c">a piece of data to trasfer across application
domains</param>
private static void LaunchNewApplicationAndTrasferData(string
appName, string entryPointAssm, string[] assemblies, ClassToMarshal c)
{
// create a new application domain
AppDomain ad = AppDomain.CreateDomain(appName);

// load the satellite assemblies
foreach (string assm in assemblies)
{
ad.Load(assm);
}

// create an instance of the IApplication type
// please note that the following call will also load the
assembly that contains that type
// which we pass as first parameter
IApplication app =
(IApplication)ad.CreateInstanceAndUnwrap(typeof(IApplication).Assembly.FullName, typeof(Application).FullName);

// we are ready to invoke a method on the other application domain
Debug.Print("result: " + app.StartExecution());

// let's move soe data around and see that it is equivalent but
not the same
// in facts here we will be comparing two alike instances of the
same class
// which leave in two different AppDomains
Debug.Print("result: " + EqualsButNotSameInstance(c,
app.MarshalClass(c)));
}

/// <summary>
/// The executable entry point.
/// </summary>
public static void Main()
{
// we take an assembly name, which we figure contains a
// type that derives from IApplication which we can create
// and invoke in a different AppDomain
// in a rel exampe this would be a diferent assembly of course,
// which we would know about from some unspecified source
string assmName = typeof(Program).Assembly.FullName;

// the last parameter would contain the complete list of all
assemblies that our main
// assembly, the one with the IApplication type, needs. In this
case there is none
LaunchNewApplicationAndTrasferData("new application domain",
assmName,
new string[0] { },
new ClassToMarshal(123,
"Hello")
);
}
}
}


Regards
Lorenzo

oenren

unread,
Nov 25, 2009, 6:03:02 AM11/25/09
to
First I like to thank you for the example, however when running your example
in MF 4.0 the program hangs at the line :

(IApplication)ad.CreateInstanceAndUnwrap(typeof(IApplication).Assembly.FullName, typeof(Application).FullName);

This behavior I recognized before in MF 4.0 so reasons enough for me to make
a switch to MF 3.0. After uninstalling 4.0 and installing 3.0 I could run
your example without hanging of the program. For now developing in MF 3.0
isn't a problem for me right now but I though you preciate a reply about this
problem in MF 4.0.

Regards,

René

0 new messages