Relating to Can I make the default AppDomain use shadow copies of certain assemblies?, it describes a working solution to activate shadow copying within the default AppDomain for a specific directory.
Basically it says to use these simple methods:
AppDomain.CurrentDomain.SetShadowCopyPath(aDirectory);
AppDomain.CurrentDomain.SetShadowCopyFiles();
But because the methods used here are marked as obsolete I was wondering what is now the correct way to accomplish the same. The warning message hints to:
Please investigate the use of AppDomainSetup.ShadowCopyDirectories instead
An AppDomain has a member of this type called SetupInformation
which might bring you to this straightforward implementation
AppDomain.CurrentDomain.SetupInformation.ShadowCopyDirectories = aDirectory;
AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles = "true";
Unfortunately this has no effect.
So the question is, is there a way to alter the AppDomainSetup of the current appdomain to activate shadow copying ?
As far as I know these methods only work on .NET Framework version 1.1. For all later versions you cannot enable shadow-copying on the main AppDomain. You need to create a new AppDomain
and set-it up appropriately. A simple approach is to create a loader application that simply:
- Creates a new AppDomain with shadow-copy enabled. For this you will have to use one of the overloads of AppDomain.CreateDomain that take an AppDomainSetup parameter.
- Executes your main application using the AppDomain.ExecuteAssembly method.
A good starting point can be found in the Shadow Copying of Applications CodeProject article. The following program is taken from the article with a slight modification (the cache path is not specified:
using System;
using System.IO;
namespace Loader
{
static class Program
{
[LoaderOptimization(LoaderOptimization.MultiDomainHost)]
[STAThread]
static void Main()
{
/* Enable shadow copying */
// Get the startup path. Both assemblies (Loader and
// MyApplication) reside in the same directory:
string startupPath = Path.GetDirectoryName(
System.Reflection.Assembly
.GetExecutingAssembly().Location);
string configFile = Path.Combine(
startupPath,
"MyApplication.exe.config");
string assembly = Path.Combine(
startupPath,
"MyApplication.exe");
// Create the setup for the new domain:
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = "MyApplication";
setup.ShadowCopyFiles = "true"; // note: it isn't a bool
setup.ConfigurationFile = configFile;
// Create the application domain. The evidence of this
// running assembly is used for the new domain:
AppDomain domain = AppDomain.CreateDomain(
"MyApplication",
AppDomain.CurrentDomain.Evidence,
setup);
// Start MyApplication by executing the assembly:
domain.ExecuteAssembly(assembly);
// After the MyApplication has finished clean up:
AppDomain.Unload(domain);
}
}
}
You will have to:
- Replace
MyApplication.exe
with the name of your executable assembly.
- Replace
MyApplication
with the name of apllication.
- Replace
MyApplication.exe.config
with the name of you application's configuration file. If you do not have one then you do not need to set this.
You do not need to create a separate application. You can just spawn sub-domain in your main method or call the actual main method based on AppDomain.CurrentDomain.IsDefaultAppDomain()
value:
public static void Main(string[] args)
{
if (AppDomain.CurrentDomain.IsDefaultAppDomain())
{
// Loader
var entryPoint = System.Reflection.Assembly
.GetExecutingAssembly();
var applicationName = entryPoint.GetName().Name;
// Create the setup for the new domain:
var setup = new AppDomainSetup();
setup.ApplicationName = applicationName;
setup.ShadowCopyFiles = "true"; // note: it isn't a bool
// Create the application domain. The evidence of this
// running assembly is used for the new domain:
AppDomain domain = AppDomain.CreateDomain(
applicationName,
AppDomain.CurrentDomain.Evidence,
setup);
try
{
// Start MyApplication by executing the assembly:
domain.ExecuteAssembly(entryPoint.Location, args);
}
finally
{
// After the MyApplication has finished clean up:
AppDomain.Unload(domain);
}
}
else
{
// Main
ActualMain(args);
}
}
public static int ActualMain(string[] args)
{
//Hello-world!
}