2011-08-19 5 views
2

je dois faire quelque chose comme ça dans C# (pseudo):Comment obtenir le parent AppDomain?

static var ns = new Non_Serializable_Nor_Marshal() 

var app = new AppDomain(); 
app.execute(foo) 

void foo() 
{ 
    var host = AppDomain.Current.Parent; //e.g. the original one 
    host.execute(bar) 
} 

void bar() 
{ 
    ns.Something(); 
} 

OIEau J'ai un non serializeable ni objet maréchal dans un appdomain. Je veux créer un deuxième domaine et exécuter foo(). De l'intérieur de ce deuxième domaine, je veux exécuter bar() sur le domaine d'origine.

Comment puis-je transmettre le domaine d'origine à l'enfant?

Répondre

5

Si vous ne souhaitez pas utiliser Interop, vous pouvez également utiliser un petit truc en utilisant AppDomainManager. Vous pouvez automatiquement "câbler" automatiquement le domaine "principal" dans n'importe quel domaine - albiet comme je le fais signifie que vous supprimez votre domaine principal réel.

Voici la classe qui fait toute la magie:

/// <summary> 
/// Represents a <see cref="AppDomainManager"/> that is 
/// aware of the primary application AppDomain. 
/// </summary> 
public class PrimaryAppDomainManager : AppDomainManager 
{ 
    private static AppDomain _primaryDomain; 

    /// <summary> 
    /// Gets the primary domain. 
    /// </summary> 
    /// <value>The primary domain.</value> 
    public static AppDomain PrimaryDomain 
    { 
     get 
     { 
      return _primaryDomain; 
     } 
    } 

    /// <summary> 
    /// Sets the primary domain. 
    /// </summary> 
    /// <param name="primaryDomain">The primary domain.</param> 
    private void SetPrimaryDomain(AppDomain primaryDomain) 
    { 
     _primaryDomain = primaryDomain; 
    } 

    /// <summary> 
    /// Sets the primary domain to self. 
    /// </summary> 
    private void SetPrimaryDomainToSelf() 
    { 
     _primaryDomain = AppDomain.CurrentDomain; 
    } 

    /// <summary> 
    /// Determines whether this is the primary domain. 
    /// </summary> 
    /// <value> 
    ///  <see langword="true"/> if this instance is the primary domain; otherwise, <see langword="false"/>. 
    /// </value> 
    public static bool IsPrimaryDomain 
    { 
     get 
     { 
      return _primaryDomain == AppDomain.CurrentDomain; 
     } 
    } 

    /// <summary> 
    /// Creates the initial domain. 
    /// </summary> 
    /// <param name="friendlyName">Name of the friendly.</param> 
    /// <param name="securityInfo">The security info.</param> 
    /// <param name="appDomainInfo">The AppDomain setup info.</param> 
    /// <returns></returns> 
    public static AppDomain CreateInitialDomain(string friendlyName, Evidence securityInfo, AppDomainSetup appDomainInfo) 
    { 
     if (AppDomain.CurrentDomain.DomainManager is PrimaryAppDomainManager) 
      return null; 

     appDomainInfo = appDomainInfo ?? new AppDomainSetup(); 
     appDomainInfo.AppDomainManagerAssembly = typeof(PrimaryAppDomainManager).Assembly.FullName; 
     appDomainInfo.AppDomainManagerType = typeof(PrimaryAppDomainManager).FullName; 

     var appDomain = AppDomainManager.CreateDomainHelper(friendlyName, securityInfo, appDomainInfo); 
     ((PrimaryAppDomainManager)appDomain.DomainManager).SetPrimaryDomainToSelf(); 
     _primaryDomain = appDomain; 
     return appDomain; 
    } 

    /// <summary> 
    /// Returns a new or existing application domain. 
    /// </summary> 
    /// <param name="friendlyName">The friendly name of the domain.</param> 
    /// <param name="securityInfo">An object that contains evidence mapped through the security policy to establish a top-of-stack permission set.</param> 
    /// <param name="appDomainInfo">An object that contains application domain initialization information.</param> 
    /// <returns>A new or existing application domain.</returns> 
    /// <PermissionSet> 
    ///  <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="ControlEvidence, ControlAppDomain, Infrastructure"/> 
    /// </PermissionSet> 
    public override AppDomain CreateDomain(string friendlyName, Evidence securityInfo, AppDomainSetup appDomainInfo) 
    { 
     appDomainInfo = appDomainInfo ?? new AppDomainSetup(); 
     appDomainInfo.AppDomainManagerAssembly = typeof(PrimaryAppDomainManager).Assembly.FullName; 
     appDomainInfo.AppDomainManagerType = typeof(PrimaryAppDomainManager).FullName; 

     var appDomain = base.CreateDomain(friendlyName, securityInfo, appDomainInfo); 
     ((PrimaryAppDomainManager)appDomain.DomainManager).SetPrimaryDomain(_primaryDomain); 

     return appDomain; 
    } 
} 

Et vous devez modifier votre Main() (entrée de l'application) légèrement:

/// <summary> 
/// The main entry point for the application. 
/// </summary> 
static void Main(string[] args) 
{ 
    new Program().Run(args); 
} 

void Run(string[] args) 
{ 
    var domain = PrimaryAppDomainManager.CreateInitialDomain("PrimaryDomain", null, null); 
    if (domain == null) 
    { 
     // Original Main() code here. 
    } 
    else 
    { 
     domain.CreateInstanceAndUnwrap<Program>().Run(args); 
    } 
} 

Maintenant, à tout moment, vous pouvez obtenir PrimaryAppDomainManager.PrimaryDomain à obtenir une référence au domaine primaire, rappelez-vous juste que ce n'est pas le domaine inital créé par le .Net runtime - c'est celui que nous créons immédiatement.

Vous pouvez consulter les commentaires dans mon blog post pour obtenir un moyen d'obtenir l'exécution .Net pour vous automatiquement à l'aide du fichier app.config.

Edit: j'ai oublié d'ajouter la méthode d'extension que je l'utilise, la voici:

/// <summary> 
/// Creates a new instance of the specified type. 
/// </summary> 
/// <typeparam name="T">The type of object to create.</typeparam> 
/// <param name="appDomain">The app domain.</param> 
/// <returns>A proxy for the new object.</returns> 
public static T CreateInstanceAndUnwrap<T>(this AppDomain appDomain) 
{ 
    var res = (T)appDomain.CreateInstanceAndUnwrap(typeof(T)); 
    return res; 
} 
0

Vous pouvez essayer de référencer mscoree, puis d'utiliser ses méthodes. Je l'ai utilisé dans un de mes projets. mscoree gardera une trace de votre AppDomains sans aucune entrée.

/// <summary> 
    /// Returns the primary application domain. 
    /// </summary> 
    /// <returns>The primary application domain.</returns> 
    public static AppDomain GetPrimaryAppDomain() 
    { 
     return GetAppDomain(Process.GetCurrentProcess().MainModule.ModuleName); 
    } 

    /// <summary> 
    /// Returns the application domain with the given friendly name. 
    /// </summary> 
    /// <param name="friendlyName">The friendly name of the application domain.</param> 
    /// <returns>The application domain with the given friendly name.</returns> 
    /// <exception cref="System.ArgumentNullException">Thrown if friendlyName is null.</exception> 
    public static AppDomain GetAppDomain(string friendlyName) 
    { 
     if (friendlyName == null) 
     { 
      throw new ArgumentNullException("friendlyName"); 
     } 
     IntPtr handle = IntPtr.Zero; 
     CorRuntimeHostClass host = new CorRuntimeHostClass(); 
     try 
     { 
      host.EnumDomains(out handle); 
      object domain = null; 
      while (true) 
      { 
       host.NextDomain(handle, out domain); 
       if (domain == null) 
       { 
        return null; 
       } 
       AppDomain appDomain = (AppDomain)domain; 
       if (appDomain.FriendlyName == friendlyName) 
       { 
        return appDomain; 
       } 
      } 
     } 
     finally 
     { 
      host.CloseEnum(handle); 
      Marshal.ReleaseComObject(host); 
      host = null; 
     } 
    } 

(Adapté de http://www.dolittle.com/blogs/einar/archive/2007/05/18/cross-appdomain-singleton.aspx)