Domanda

Ho cercato di ottenere il seguente codice per il lavoro (tutto è definito nello stesso assembly):

namespace SomeApp{

public class A : MarshalByRefObject
{
   public byte[] GetSomeData() { // }
}

public class B : MarshalByRefObject
{
   private A remoteObj;

   public void SetA(A remoteObj)
   {
      this.remoteObj = remoteObj;
   }
}

public class C
{
   A someA = new A();
   public void Init()
   {
       AppDomain domain = AppDomain.CreateDomain("ChildDomain");
       string currentAssemblyPath = Assembly.GetExecutingAssembly().Location;
       B remoteB = domain.domain.CreateInstanceFromAndUnwrap(currentAssemblyPath,"SomeApp.B") as B;
       remoteB.SetA(someA); // this throws an ArgumentException "Object type cannot be converted to target type."
   }
}

}

Quello che sto cercando di fare è passare un riferimento di un'istanza 'A' creata nel primo AppDomain al dominio figlio e avere il dominio figlio eseguire un metodo sul primo dominio. In un certo punto sul codice 'B' Vado a chiamata 'remoteObj.GetSomeData ()'. Questo deve essere fatto perché la 'byte []' dal metodo 'GetSomeData' deve essere 'calcolato' il primo dominio applicazione.   Cosa devo fare per evitare l'eccezione, o che cosa posso fare per ottenere lo stesso risultato?

È stato utile?

Soluzione

posso duplicare il problema, e sembra essere correlato alla TestDriven.net e / o xUnit.net. Se corro C.Init () come metodo di prova, ottengo lo stesso messaggio di errore. Tuttavia, se corro C.Init () da un'applicazione di console, non ottengo l'eccezione.

Stai vedendo la stessa cosa, in esecuzione C.Init () da un test di unità?

Edit: Sono anche in grado di duplicare il problema utilizzando NUnit e TestDriven.net. Sono anche in grado di duplicare l'errore utilizzando il corridore NUnit invece di TestDriven.net. Così il problema sembra essere correlato a eseguire il codice attraverso un framework di test, anche se non so perché.

Altri suggerimenti

La causa principale effettivo è stato la DLL è stata sempre caricato da varie località in due diversi domini app. Questo cause .NET a pensare che sono diverse assemblee che di mezzi naturalmente le tipologie sono diverse (anche se hanno lo stesso nome della classe, dello spazio dei nomi, ecc).

Il motivo di prova di Jeff fallito quando viene eseguito attraverso un quadro di unit test è perché framework di unit test creano generalmente AppDomain con ShadowCopy impostato su "true". Ma il vostro creato manualmente AppDomain stabilizzerebbe a ShadowCopy = "false". Ciò causerebbe le DLL per essere caricati da diverse posizioni che porta alla bella "tipo di oggetto non può essere convertito nel tipo di destinazione." di errore.

UPDATE: Dopo ulteriori test, sembra venire giù alla ApplicationBase essere diverso tra le due AppDomain. Se corrispondono, poi le opere scenario di cui sopra. Se sono diversi esso non (anche se ho confermato che la DLL viene caricato in entrambi i AppDomain dalla stessa directory utilizzando WinDbg) Inoltre, se accendo ShadowCopy = "true" in entrambi i miei AppDomain, poi fallisce con un messaggio diverso:. "System.InvalidCastException: oggetto deve implementare IConvertible"

UPDATE2: porta ulteriore lettura farmi credere che è legato alla Contesti . Quando si utilizza uno dei "Da" metodi (Assembly.LoadFrom, o appDomain.CreateInstanceFromAndUnwrap), se l'assemblea si trova in uno dei percorsi di carico normali (l'ApplicationBase o uno dei percorsi di sondaggio) allora è caricato nel predefinito Load Context. Se il gruppo non viene trovato, allora è caricato nel Load-Da Context. Così, quando entrambe le AppDomain sono uguagliano ApplicationBase di, quindi anche se si usa un "Da" il metodo, sono entrambi caricati nel loro rispettivo contesto Load Default di dominio di applicazione. Ma quando i di ApplicationBase sono diversi, allora si AppDomain avrà l'assemblea nel suo contesto Load Default mentre l'altro ha l'assemblea in esso di carico-Da Contesto.

Questo è un commento a @RussellMcClure ma come è di complessa per un commento inserisco questo come una risposta:

Sono all'interno di un'applicazione ASP.NET e spegnendo ombra-copy (che sarebbe anche risolvere il problema) non è davvero un'opzione, ma ho trovato la seguente soluzione:

AppDomainSetup adSetup = new AppDomainSetup();
if (AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles == "true")
{
    var shadowCopyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (shadowCopyDir.Contains("assembly"))
        shadowCopyDir = shadowCopyDir.Substring(0, shadowCopyDir.LastIndexOf("assembly"));

    var privatePaths = new List<string>();
    foreach (var dll in Directory.GetFiles(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, "*.dll"))
    {
        var shadowPath = Directory.GetFiles(shadowCopyDir, Path.GetFileName(dll), SearchOption.AllDirectories).FirstOrDefault();
        if (!String.IsNullOrWhiteSpace(shadowPath))
            privatePaths.Add(Path.GetDirectoryName(shadowPath));
    }

    adSetup.ApplicationBase = shadowCopyDir;
    adSetup.PrivateBinPath = String.Join(";", privatePaths);
}
else
{
    adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    adSetup.PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
}

Questa utilizzerà la directory shadow-copy dei principali app-dominio come l'applicazione-base e aggiungere tutti i gruppi d'ombra-copiato il percorso privato, se shadow-copy è attivato.

Se qualcuno ha un modo migliore di fare questo la prego di dirmi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top