1

I am having a problem with Marshalling an object across application domains in a .NET Windows Service.

I have created two app's that marshal an object across an app domain and run code through a proxy MarshalByRefObject

The first application was a simple proof of concept since I do not have a lot of experience with marshalling across application domains. It contains a single project where the MarshalByRefObject is defined in the same namespace as the rest of the project. This app works fine, using almost the same code as my other app. The main difference is that the class I am Marshalling in the second app is defined in another Namespace.

The other project is more complex, it is a Windows Service with multiple projects. The main Windows Service loads a library that that does the marshalling. The class type of the Marshal target type is defined in another library, so I use the fully qualified namespace/class name.

The problem I am facing is that when it gets to the last line of the code below it throws an exception:

Could not load CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler from assembly ProductNameService where product name is the main Windows Service class.

The Code:

AppDomain compilerDomain = null;
AppDomainSetup compilerDomainSetup;
CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler scriptCompiler;

...

// Setup a seperate AppDomain 
compilerDomainSetup = new AppDomainSetup();
exeAssembly = Assembly.GetEntryAssembly().FullName;
compilerDomainSetup.ApplicationBase = System.Environment.CurrentDirectory;

compilerDomainSetup.DisallowBindingRedirects = false;
compilerDomainSetup.DisallowCodeDownload = true;
compilerDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
compilerDomain = AppDomain.CreateDomain("LiveLinkCSScriptDomain", null, compilerDomainSetup);

// Create an instance of the MarshalByRefScriptCompiler in the other AppDomain
scriptCompiler = (CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler)compilerDomain.CreateInstanceAndUnwrap(exeAssembly, typeof(CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler).FullName);

I have done research on this exception and almost everything I find says that it is a problem with versioning of the DLL, however my DLL's are not in the GAC, and there are no other versions installed. I am doing a clean build and installing the service with installutil.

I used the MSDN documentation as a guide for creating the code that does the marshalling

I am wondering if there is an issue with loading the MarshalByRefScriptCompiler because the type is in another library. I am able to create a MarshalByRefScriptCompiler in a simple winforms app, but I get the exception in my windows service.

Any tips or insight would be greatly appreciated!

Russell McClure
  • 4,821
  • 1
  • 22
  • 22
dmck
  • 7,801
  • 7
  • 43
  • 79

2 Answers2

2

I should be able to help you. I've spent many hours recently (How do I pass references as method parameters across AppDomains?) working on different cross appdomain marshaling problems. My first suggestion would be to try using CreateInstanceFromAndUnwrap instead of CreateInstanceAndUnwrap.

I'm also a little wary of this line:

compilerDomainSetup.ApplicationBase = System.Environment.CurrentDirectory;

How is your original AppDomain being created? Are you hosted in IIS, in which case your original AppDomain will be using ShadowCopy? Are all the dlls involved in a single folder?

EDIT:

To summarize, you can use CreateInstanceAndUnwrap if your compilerDomainSetup.ApplicationBase is set to the directory containing your dll and you pass in the correct first param (e.g. typeof(MarshalByRefScriptCompiler).Assembly.FullName).

Or, you can use CreateInstanceFromAndUnwrap and just pass in the location (e.g. typeof(MarshalByRefScriptCompiler).Assembly.Location) of the containing assembly as the first param.

Community
  • 1
  • 1
Russell McClure
  • 4,821
  • 1
  • 22
  • 22
  • Thanks for the response. I changed the ApplicationBase to: `compilerDomainSetup.ApplicationBase = @"C:\ServiceSchedulerDebug\Debug";` which is where all the DLLs are (all in a single folder). However in the exception is still shows it looking in C:\Windows\System32. Any ideas? – dmck Oct 25 '11 at 14:41
  • Almost sounds like your change didn't get picked up. Your windows service is running in the C:\ServiceSchedulerDebug\Debug folder? – Russell McClure Oct 25 '11 at 14:55
  • Yes, I am doing a debug build and installing with installutil from the command line. The service is installed in C:\ServiceScheduler\Debug (changed the dir). AppDomain.CurrentDomain.BaseDirectory is C:\ServiceScheduler\Debug. I'm still trying to figure out why it's looking in C:\Windows\System32, I think this is causing the problem. – dmck Oct 25 '11 at 15:48
  • You need to use CreateInstanceFromAndUnwrap and pass in the path to the dll as the first param: typeof(MarshalByRefScriptCompiler).Assembly.Location – Russell McClure Oct 25 '11 at 16:06
  • Running a service through windows, the working directory is the windows\system directory. That's why you're seeing that behaviour. – Chris Stavropoulos Oct 25 '11 at 18:10
1

As a starting point, you could try Process Monitor to determine where it's trying to load your missing type from. It's very possible that it's as simple as it looking in the wrong directory for your assembly.

svick
  • 236,525
  • 50
  • 385
  • 514
Chris Stavropoulos
  • 1,766
  • 13
  • 27