views:

266

answers:

3

I am trying to run automated tests on a particular product. The test consists of installing the product into different locations on the hard drive and then performing some operations on it and then closing the application.

The code that launches the process looks like this:

using (Process process = new Process())
            {
                process.StartInfo.FileName = "C:\mylocation\myapp.exe";
                process.Start();
            }

While executing the tests continuously, when the install location of the application changes, I get an exception from the above code that says:

API restriction: The assembly 'file:///C:\alternate_location\myapp.exe' has already loaded from a different location. It cannot be loaded from a new location within the same appdomain.

The tests cannot be run continuously because of this.

What can be done to overcome this? Is there anyway I can unload assemblies form the GAC?

Can I do something in my test application to overcome this OR does something have to be changed in the application that I am testing?

+1  A: 

You can't unload assemblies from an application domain once loaded. But you could create a new application domain (AppDomain class), load the assemblies within it, use them, then unload the domain. See here: http://stackoverflow.com/questions/97433/good-example-of-use-of-appdomain

Konamiman
This has nothign to do with AppDomains. Her's referring to the GAC
Ruben Bartelink
Can the +1er please explain the relevance of the answer? (I'll remove my comments and/or -1 if there's a good reason...)
Ruben Bartelink
Re-read question, it has everything to do with AppDomains and little to do with the GAC. Sadly too late to undo my -1... Can someone throw in a +1 to undo please :P
Ruben Bartelink
You can +1 on any of my responses on other questions to compensate, altough I don't know if this is considered legal/ethical in SO :-)
Konamiman
So are you suggesting that i run each test case in a separate app domain or something like that?
Poulo
@Konamiman: Cancassing will disqualify :P I'm sure Karma will sort you out for your loss of points - I was more concerned that your answer, which I should have +1'd gets to its rightful place in the vote-order! (Off now to find something of yours to +1!)
Ruben Bartelink
@Poulo: That would be at least worth to try.
Konamiman
@Poulo: You still havent said what your test rig/framework is. Bottom line is you're not going to be able to load the same assembly into a single AppDomain, so you need to route around that fact, either by explictly creating separate ones, or maybe by executing each test in a separate process etc. I depends on what you're doing -- so you need to explain more if you need a precise answer
Ruben Bartelink
+1  A: 

Adding something to the GAC is not an intrinsic part of the component's definition - it's generally done by an installer etc.

The gacutil tool can be used to remove your tool from the GAC. In 1.1, it was in the Framework dir. In newer versions, its in the SDK, e.g., C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin

Ruben Bartelink
But, I do uninstall the application after each test case. (otherwise I would not be allowed to install another copy of it) So should'nt the uninstall take care of removing it also, if the installing added the assembly to the GAC?Also, I do not seem to be able to reproduce the issue while doing the tests manually. So it seems like a timing issue.So do you suggest using the tool to remove the assembly from the GAC after each test case?This might not be viable for me, because I run the tests on machines that have only the .NET framework installed. (No VS and SDK)Is there any ohter way out?
Poulo
Sounds like there's a lot of confusion here. You sure you're putting stuff into the GAC? The exception you're getting is related to trying to load the same DLL twice from different locations into the same AppDomain - which might be due to multiple Tests being run in the same [AppDomain] context. Konamiman's answer is correct. You should expand your question to explain what framework / mechanism you're using to execute the tests - That'll be the key to figuring out the best way to isolate the exections from eachother appropriately. When you say 'installing', what to you mean, installutil? MSI?
Ruben Bartelink
Sorry.Here is what is happening. I have a test application that executes test cases one after the other. The test cases are basically methods of a class. The tests are aimed at testing an installer of a product. So each test case installs the product using an InstallShield installer, then to verify, I launch the application (that was installed) using the method I have described in the question. I do some basic operations and then close the application and uninstall it. The next test case repeats the same thing, except that the application is installed into another location. ...continued
Poulo
continued... In this case, I get the exception. I am NOT deliberately putting stuff into the GAC.
Poulo
@Poulo: Then I suggest removing the word GAC from your question. Sounds like the problem is that you are dynamically loading a .NET class into your test app. This assembly stays in your appdomain forever, and there's no way to unload it. Workaround is either to make sure you load into a separate appdomain [which you then unload when finished with], or to shell out to another EXE, achieving the same result. This is exactly what Konamiman said, so go +1 him (but I assume that was you)!
Ruben Bartelink
Thank you Konamiman and Ruben.@Ruben: Yup, you guessed right!
Poulo
@Poulo: A good opportunity to up your Accept rate :P
Ruben Bartelink
A: 

Could you provide more information for us? I haven't been able to reproduce this error.

Process.Start should create a new process with its own AppDomain.

On my machine I created a project Harness which has a project reference to DoNothing which is a strongly signed assembly and a project reference to LaodDoNothing which has a reference to c:\DoNothing.exe. I've pasted the code below from Harness.Main with debug outputs as inline comments. The exes suffixed with unsigned are not signed.

//debug outputs when Main is jitted:'Harness.vshost.exe' (Managed): Loaded 'c:\project\DoNothing\Harness\bin\Debug\DoNothing.exe', Symbols loaded.
//debug outputs when Main is jitted:'Harness.vshost.exe' (Managed): Loaded 'c:\project\DoNothing\Harness\bin\Debug\LoadDoNothing.exe', Symbols loaded.

ZaZaZa.Main();
LoadDoNothing.Program.Main();
using (Process process = new Process())
{
    process.StartInfo.FileName = @"C:\donothingunsigned.exe";
    process.Start(); //debug outputs The thread 0x17f0 has exited with code 0 (0x0).  No assemblies loads are logged to debug because this is a separate process.


}

using (Process process = new Process())
{
    process.StartInfo.FileName = @"C:\3\donothingunsigned2.exe";
    process.Start(); //Debug outputs The thread 0x1014 has exited with code 0 (0x0). No assemblies loads are logged to debug because this is a separate process.
}
AppDomain.CurrentDomain.ExecuteAssembly(@"C:\donothingunsigned.exe"); //debug outputs 'Harness.vshost.exe' (Managed): Loaded 'C:\donothingunsigned.exe'
AppDomain.CurrentDomain.ExecuteAssembly(@"C:\3\donothingunsigned2.exe"); //no debug output because the loader realizes this assembly has already been loaded and uses that.
David Silva Smith
I did not exactly understand what you are trying to convey. But I did notice that you have started two different executables 'donothingunsigned.exe' and 'donothingunsigned2.exe'. My problem is associated with trying to start the same executable from different locations. That is what gives me the exception under the circumstances that I have mentioned in the question as well as later comments.
Poulo
I was unable to reproduce the error using the above methods. Processes don't share appdomains so I don't see how Process.Start() could cause your error.
David Silva Smith