Okay, after racking our brains against the wall here, we finally figured it out. It's an issue that can rear its head if you want to create a COM object that dynamically loads assemblies (not strongly named), and/or uses remoting and transparent proxies to cross an AppDomain.
Here's the situation: The assembly that's registered for COM had the three types listed below. The interface was used as the explicit COM interface definition. Those files were located in some random directory (user-selected upon install or during development in the bin\debug dir). I did not, and do not, want to put any files (including a .config file) in the application directory of the application calling the COM object. Here's why the problem occurs. The AppBase of the DefaultDomain created by the interop is set to the directory of the calling application. Since my assemblies were not in that directory (or a subdir), any call that needed to read the assembly, for unwrapping a transparent proxy, or to load another assembly dynamically, the system couldn't find the types. In the case of the transparent proxy, it searches the DefaultDomain's AppBase/PrivateAppBase for the Assembly--even though the type is currently present in the loaded assembly. In the case of dynamically loading, that's more straight-forward; it would be a security breach for an assembly to be dynamically loaded outside of the AppDomain's paths. That's one reason why I wanted to create another domain to begin with, so that I could specify my own AppBase and .config file. The solution was as follows. I put the COM object in the GAC, and that solved the problem. Since it was inside of the COM object that it creates the proxy to my AppDomain, if it's in the GAC it'll find the type to unwrap the proxy. Granted, I didn't want to put it in the GAC, but that was the only solution that worked. What that left though was no dynamic way to determine where the rest of my assemblies are to set the AppBase. Before, I was using GetExecutingAssembly().Location, but since it's now running in the GAC, that doesn't help. My temporary solution was to just set a registry key pointing to the installed location of my files and have the COM assembly read that to set the AppBase. If anyone has any better ideas, I'm all ears. This scenario would seem to apply not to just COM objects though. If anyone wanted to write an Add-In for a 3rd party application (one that supports add-in's), I would think that best practices would be to put your add-in in your own directory and not the application directory. In that case, your add-in would need to create its own AppDomain and call it via a proxy. Hope this post helps someone else in the future :) --Oren > -----Original Message----- > From: Moderated discussion of advanced .NET topics. [mailto:ADVANCED- > [EMAIL PROTECTED]] On Behalf Of Oren Novotny > Sent: Tuesday, January 21, 2003 12:00 PM > To: [EMAIL PROTECTED] > Subject: InvalidCast with AppDomain.CreateInstanceAndUnwrap > > I'm getting a strange InvalidCastException when I try to convert the = > object > I get from an AppDomain.CreateInstanceAndUnwrap call. What I'm trying = > to do > is create a proxy object in my own AppDomain so that I can define my own > AppBase and config file. =20 > > Now, the assembly is loaded, and I can tell because of the constructor > outputs in the debug console, and I can get an "object" out of the > CreateAndUnwrap. But, if I try to cast it either to the implemented > interface or even just the object itself, I get an InvalidCastException. > > Any ideas? > > Thanks, > --Oren > > > class TraceabilityAddIn : MarshalByRefObject, ITraceabilityAddIn > { > ... > } > > interface ITraceabilityAddIn { ... } > > > class TraceabilityAddInProxy : ITraceabilityAddIn=20 > { > ITraceabilityAddIn _AddIn; > void Init() { > // Get the path we're executing in > string path =3D new > System.IO.FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryNam= > e; > > AppDomainSetup setup =3D new AppDomainSetup(); > setup.ApplicationBase =3D path; > setup.ApplicationName =3D "Traceability AddIn"; > setup.ConfigurationFile =3D "Traceability.config"; > > AppDomain ad =3D AppDomain.CreateDomain("TraceabilityDomain" , null, = > setup); > > try > { > _AddIn =3D > (ITraceabilityAddIn)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssem= > bly > ().FullName, typeof(TraceabilityAddIn).FullName); =09 > =09 > // It doesn't matter whether I hard-code the assembly and type name or = > not > //_AddIn =3D > (ITraceabilityAddIn)ad.CreateInstanceAndUnwrap("Traceability.AddIn", > "Traceability.AddIn.TraceabilityAddIn"); =09 > > } > catch(Exception e) > { > // I get an exception--I shouldn't > Debug.WriteLine(e.Message); > Debug.WriteLine(e.StackTrace); > } > > } > } > > You can read messages from the Advanced DOTNET archive, unsubscribe from > Advanced DOTNET, or > subscribe to other DevelopMentor lists at http://discuss.develop.com. You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced DOTNET, or subscribe to other DevelopMentor lists at http://discuss.develop.com.
