Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the right way to set shadow copying for the default AppDomain

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 ?

like image 490
Bluesky Avatar asked Sep 20 '12 13:09

Bluesky


2 Answers

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!
}
like image 196
Mariusz Jamro Avatar answered Oct 01 '22 05:10

Mariusz Jamro


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.
like image 22
Panos Rontogiannis Avatar answered Oct 01 '22 05:10

Panos Rontogiannis