none
How to subscribe Event from secondary AppDomain? RRS feed

  • Question

  • Hello All,

    Today, I've met one problem needs your help:-)

    My app can simplify  into 3 blocks:

    X - one excuteable application(Console application), it developed by another team
    Y - One wrapper component, deployed into GAC so X will not perform "local copy" when compiling.
    Z - one core biz component.

    So the relationship among them is:

    X calls Y, Y starts secondary AppDomain by copying all Z used assemblies into one temporary  folder and creates instance, and accesses methods provided by Z.

    Now, everything is okay, except subscribe Event.

    Inside X, it'll subscribe one Event published by Y, and Y passes this Event into Z, Z will finanlly fire event.

    Now, problem comes, I cannot run X as it reports that cannot load X from Y;

    But if I copy X into Z side, then, when Y starts secondary AppDomain, it'll copy both X and Z into one temporary folder, and everything works well.

    So to X, how to subscribe event published by Y (tp Z)?

    P.S. If X does not subscribe event, everything also works well.

    Some log message attached:

    System.Reflection.TargetInvocationException was unhandled
      Message="Exception has been thrown by the target of an invocation."
      Source="mscorlib"
      StackTrace:
        Server stack trace:
           at System.RuntimeMethodHandle._SerializationInvoke(Object target, SignatureStruct& declaringTypeSig, SerializationInfo info, StreamingContext context)
           at System.Reflection.RuntimeConstructorInfo.SerializationInvoke(Object target, SerializationInfo info, StreamingContext context)
           at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
           at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
           at System.Runtime.Serialization.ObjectManager.DoFixups()
           at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream stm)
           at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeMessageParts(MemoryStream stm)
           at System.Runtime.Remoting.Messaging.SmuggledMethodCallMessage.FixupForNewAppDomain()
           at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoDispatch(Byte[] reqStmBuff, SmuggledMethodCallMessage smuggledMcm, SmuggledMethodReturnMessage& smuggledMrm)
           at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatchCallback(Object[] args)
        Exception rethrown at [0]:
           at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
           at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
           at HP.ActiveCheckLocalMode.ServiceInterface.IUpdate.add_UpdateObjProgressChanged(EventHandler`1 value)
           at HP.ActiveCheckLocalMode.SessionManager.ActiveCheckManager.UpdateObjAsync(Boolean sessionLock, Boolean debug)
           at Program.RefreshObj() in D:\Kent\Dev\Test\ConsoleApplication1\Program.cs:line 100
           at Program.TestACLM() in D:\Kent\Dev\Test\ConsoleApplication1\Program.cs:line 56
           at Program.Main(String[] args) in D:\Kent\Dev\Test\ConsoleApplication1\Program.cs:line 16
      InnerException: System.IO.FileNotFoundException
           Message="Could not load file or assembly 'ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
           Source="mscorlib"
           FileName="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
           FusionLog="=== Pre-bind state information ===\r\nLOG: User = Kent-PC\\Kent\r\nLOG: DisplayName = ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\n (Fully-specified)\r\nLOG: Appbase = file:///C:/Users/Kent/AppData/Local/Temp/ACLM/HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager_d90dba57-cede-4db4-a210-2eaabd89a036\r\nLOG: Initial PrivatePath = D:\\Kent\\Dev\\Test\\ConsoleApplication1\\bin\\Debug\\;C:\\Users\\Kent\\AppData\\Local\\Temp/ACLM/HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager_d90dba57-cede-4db4-a210-2eaabd89a036\r\nCalling assembly : (Unknown).\r\n===\r\nLOG: This bind starts in default load context.\r\nLOG: No application configuration file found.\r\nLOG: Using machine configuration file from C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\config\\machine.config.\r\nLOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).\r\nLOG: Attempting download of new URL file:///C:/Users/Kent/AppData/Local/Temp/ACLM/HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager_d90dba57-cede-4db4-a210-2eaabd89a036/ConsoleApplication1.DLL.\r\nLOG: Attempting download of new URL file:///C:/Users/Kent/AppData/Local/Temp/ACLM/HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager_d90dba57-cede-4db4-a210-2eaabd89a036/ConsoleApplication1/ConsoleApplication1.DLL.\r\nLOG: Attempting download of new URL file:///C:/Users/Kent/AppData/Local/Temp/ACLM/HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager_d90dba57-cede-4db4-a210-2eaabd89a036/ConsoleApplication1.EXE.\r\nLOG: Attempting download of new URL file:///C:/Users/Kent/AppData/Local/Temp/ACLM/HP.ActiveCheckLocalMode.UpdateEngine.UpdateManager_d90dba57-cede-4db4-a210-2eaabd89a036/ConsoleApplication1/ConsoleApplication1.EXE.\r\n"
           StackTrace:
                at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
                at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
                at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
                at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
                at System.Reflection.Assembly.Load(String assemblyString)
                at System.Reflection.MemberInfoSerializationHolder..ctor(SerializationInfo info, StreamingContext context)
           InnerException:


    Thanks,
    Kent
    • Edited by Kent.zhou Friday, August 7, 2009 12:22 PM Add log message
    Friday, August 7, 2009 12:12 PM

Answers

  • Looks to me like the secondary AppDomain's AppDomainSetup isn't initialized correctly.  Your .exe appears to be running from D:\Kent\Dev\Test\ConsoleApplication1\bin\Debug but the CLR is searching for ConsoleApplication1 in c:\Users\Ken\AppData\Local\Temp.  Check this MSDN page for details, use Fuslogvw.exe for trouble-shooting.
    Hans Passant.
    • Marked as answer by eryang Friday, August 14, 2009 7:36 AM
    Friday, August 7, 2009 5:02 PM
    Moderator
  • Thanks for your reply.

    It caused by that secondary AppDomain wants to know the methods(From .exe) consuming the events, now I sunscribed one event AssemblyResolve of AppDomain like below:

     

    private

     

    static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)

    {

     

    Assembly result = null;

     

    string shortAssemblyName = args.Name.Substring(0, args.Name.IndexOf(','));

     

    string dllFileName = shortAssemblyName + ".dll";// Path.Combine(privateBinPath, shortAssemblyName + ".dll");

     

    string exeFileName = shortAssemblyName + ".exe";// Path.Combine(privateBinPath, shortAssemblyName + ".exe");

     

    if (File.Exists(dllFileName))

    {

    result =

    Assembly.LoadFrom(dllFileName);

    }

     

    else if (File.Exists(exeFileName))

    {

    result =

    Assembly.LoadFrom(exeFileName);

    }

     

    else

    {

    result =

    Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;

    }

     

    return result;

    }

     



    then everything works well.

    Not understand why it can work, MS framework is one black box for me, not like Java. Perhaps I need to read IL for further information.

    Thanks,
    Kent

    • Edited by Kent.zhou Monday, August 10, 2009 2:52 AM
    • Marked as answer by eryang Friday, August 14, 2009 7:35 AM
    Monday, August 10, 2009 2:45 AM

All replies

  • Looks to me like the secondary AppDomain's AppDomainSetup isn't initialized correctly.  Your .exe appears to be running from D:\Kent\Dev\Test\ConsoleApplication1\bin\Debug but the CLR is searching for ConsoleApplication1 in c:\Users\Ken\AppData\Local\Temp.  Check this MSDN page for details, use Fuslogvw.exe for trouble-shooting.
    Hans Passant.
    • Marked as answer by eryang Friday, August 14, 2009 7:36 AM
    Friday, August 7, 2009 5:02 PM
    Moderator
  • Thanks for your reply.

    It caused by that secondary AppDomain wants to know the methods(From .exe) consuming the events, now I sunscribed one event AssemblyResolve of AppDomain like below:

     

    private

     

    static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)

    {

     

    Assembly result = null;

     

    string shortAssemblyName = args.Name.Substring(0, args.Name.IndexOf(','));

     

    string dllFileName = shortAssemblyName + ".dll";// Path.Combine(privateBinPath, shortAssemblyName + ".dll");

     

    string exeFileName = shortAssemblyName + ".exe";// Path.Combine(privateBinPath, shortAssemblyName + ".exe");

     

    if (File.Exists(dllFileName))

    {

    result =

    Assembly.LoadFrom(dllFileName);

    }

     

    else if (File.Exists(exeFileName))

    {

    result =

    Assembly.LoadFrom(exeFileName);

    }

     

    else

    {

    result =

    Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;

    }

     

    return result;

    }

     



    then everything works well.

    Not understand why it can work, MS framework is one black box for me, not like Java. Perhaps I need to read IL for further information.

    Thanks,
    Kent

    • Edited by Kent.zhou Monday, August 10, 2009 2:52 AM
    • Marked as answer by eryang Friday, August 14, 2009 7:35 AM
    Monday, August 10, 2009 2:45 AM
  • Well, it's a workaround, not the solution.  You won't find it by reading IL.

    Hans Passant.
    Monday, August 10, 2009 8:29 AM
    Moderator