Pregunta

He estado tratando de conseguir el código siguiente para el trabajo (todo lo que se define en el mismo conjunto):

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."
   }
}

}

Lo que estoy tratando de hacer es pasar una referencia de una instancia 'A' creado en el primer dominio de aplicación al dominio secundario y tienen el dominio secundario ejecutar un método en el primer dominio. En algún momento en el código 'B' Voy a la llamada de remoteObj.GetSomeData () '. Esto se tiene que hacer, porque el 'byte []' del método 'GetSomeData' debe 'calcula' en el primer dominio de aplicación. ¿Qué debo hacer para evitar la excepción, o qué puedo hacer para conseguir el mismo resultado?

¿Fue útil?

Solución

Me puede duplicar el problema, y ??parece estar relacionado con TestDriven.net y / o xUnit.net. Si me quedo C.Init () como método de ensayo, me sale el mismo mensaje de error. Sin embargo, si me quedo C.Init () desde una aplicación de consola, no consigo la excepción.

¿Usted está viendo lo mismo, corriendo C.Init () a partir de una prueba de unidad?

Editar: Yo también soy capaz de duplicar el problema utilizando NUnit y TestDriven.net. También soy capaz de duplicar el error utilizando el corredor NUnit en lugar de TestDriven.net. Por lo que el problema parece estar relacionado con la ejecución de este código a través de un marco de pruebas, aunque no estoy seguro de por qué.

Otros consejos

La causa real fue su DLL se estaba cargada desde diferentes ubicaciones en los dos dominios de aplicaciones diferentes. Este .NET causas que piensan que son diferentes montajes que por medio del curso los tipos son diferentes (a pesar de que tienen el mismo nombre de la clase, espacio de nombres, etc.).

La razón por la prueba de Jeff falló cuando se ejecuta a través de un marco de unidad de prueba se debe a que los marcos de pruebas unitarias en general, crear dominios de aplicación con el conjunto ShadowCopy a "true". Sin embargo, su dominio de aplicación sería creada manualmente por defecto a ShadowCopy = "falso". Esto haría que los DLL que se cargan desde diferentes lugares que conduce a la agradable "Tipo de objeto no se puede convertir a tipo de destino." error.

ACTUALIZACIÓN: Después de más pruebas, parece que bajar a la ApplicationBase ser diferente entre los dos dominios de aplicación. Si coinciden, entonces los trabajos escenario anterior. Si son diferentes, no (a pesar de que he confirmado que el DLL se carga en ambos dominios de aplicación desde el mismo directorio usando windbg) hace Además, si enciendo ShadowCopy = "true" en mis dos dominios de aplicación, a continuación, se produce un error con un mensaje diferente: "System.InvalidCastException: el objeto debe implementar IConvertible"

Update2: además conduce lectura que yo creo que está relacionado con Contextos . Cuando se utiliza uno de los "De" métodos (Assembly.LoadFrom, o appDomain.CreateInstanceFromAndUnwrap), si el conjunto se encuentra en una de las trayectorias de carga normal (la ApplicationBase o una de las trayectorias de sondeo) entonces es cargado en el defecto Contexto de carga. Si el conjunto no se encuentra allí, entonces se carga en el carga-por el contexto. Por eso, cuando ambos dominios de aplicación se emparejan de ApplicationBase, a continuación, a pesar de que usamos una "Desde" método, ambos están cargados en su respectiva carga por defecto Contexto del dominio de aplicación. Pero cuando la década de ApplicationBase son diferentes, entonces un dominio de aplicación tendrá el conjunto en su defecto Contexto de carga, mientras que el otro tiene la asamblea en ella de carga-por el contexto.

Este es un comentario a @RussellMcClure pero como es a lo complejo de un comentario puedo enviar esto como una respuesta:

estoy dentro de una aplicación ASP.NET y apagar copia sombra (que también resolvería el problema) no es realmente una opción, pero me encontré con la siguiente solución:

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;
}

Esto utilizará el directorio de copia sombra de la principal aplicación en el dominio como la aplicación de la base y añadir todos los conjuntos de sombra-copiado en el camino privado si está habilitada la copia sombra.

Si alguien tiene una mejor forma de hacer esto por favor dígame.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top