теневое копирование, чтобы не блокировать сборку - PullRequest
6 голосов
/ 27 июня 2011

Я создал тестовую библиотеку

public class Test
{
    public int Add(int val1, int val2)
    {
        return val1 + val2;
    }
}

И проект, чтобы назвать это:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace Loader
{
    class Program
    {
        static void Main(string[] args)
        {
            String path = @"...Lib.dll"; // path to lib
            var name = Path.GetFileName(path);

            AppDomainSetup setup = new AppDomainSetup  
            {
                ApplicationBase = @"...", // directory where Lib.dll is 
                ShadowCopyFiles = "true",
                ShadowCopyDirectories = @"..."// directory where Lib.dll is 
            };  

            var appdomain = AppDomain.CreateDomain("Loader." + name, null, setup);
            Assembly ass = Assembly.LoadFile(path); // <--- I think here is the problem, here where assembly is locked
            Assembly assembly = appdomain.Load(ass.FullName);

            dynamic a = assembly.CreateInstance("Lib.Test");

            Console.WriteLine(a.Add(1, 5));
        }
    }
}

Пожалуйста, помогите узнать, что я сделал не так? Почему моя сборка заблокирована?

РЕДАКТИРОВАТЬ: с жестко закодированным названием сборки:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace Loader
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomainSetup ads = new AppDomainSetup();

            String fullPath = @"c:\users\myuser\documents\visual studio 2010\Projects\ShadowCopy\Loader\bin\Debug\Lib.dll";

            ads.ShadowCopyFiles = "true";
            ads.ApplicationName = "AppName";
            ads.ShadowCopyDirectories = Path.GetDirectoryName(fullPath);
            //ads.ApplicationBase = Path.GetDirectoryName(fullPath);
            //ads.PrivateBinPath = Path.GetDirectoryName(fullPath);
            ads.CachePath = @"c:\users\myuser\documents\visual studio 2010\Projects\ShadowCopy\Loader\bin\Debug\Cache\";

            AppDomain ad = AppDomain.CreateDomain("myName" + ads.ApplicationName, null, ads);

            ad.AssemblyResolve += new ResolveEventHandler( ad_AssemblyResolve );

            Console.WriteLine(ad.ShadowCopyFiles);
            Console.WriteLine(ad.SetupInformation.ShadowCopyDirectories);

            try
            {
                //Assembly assembly = ad.Load(AssemblyName.GetAssemblyName(fullPath));
                //dynamic obj = ad.CreateInstanceAndUnwrap(assembly.GetName().Name, "Lib.Test");

                dynamic obj = ad.CreateInstanceAndUnwrap("Lib", "Lib.Test");

                Console.WriteLine(obj.Add(1, 7));

                Console.ReadKey();

                Console.WriteLine(obj.Add(1, 90));
            }
            catch( Exception e)
            {
                Console.WriteLine( e.Message );
            }
        }

        static Assembly ad_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            return Assembly.LoadFile(@"c:\users\myuser\documents\visual studio 2010\Projects\ShadowCopy\Loader\bin\Debug\Lib.dll");
        }
    }
}

Интересно, что кешируемая сборка также заблокирована.

РЕДАКТИРОВАТЬ 2:

Вот строка кода для блокировки сборки

Console.WriteLine(obj.Add(1, 7));

Таким образом, при доступе к методу в Lib.Test все блокируется.

Какое может быть решение?

Ответы [ 2 ]

1 голос
/ 27 июня 2011

Вы загружаете сборку в свой основной домен приложений при запуске Assembly.LoadFile(), который блокирует файл.Если вы хотите загрузить его непосредственно в свой домен приложений, вам нужно использовать AppDomain.Load() напрямую, что позволяет домену приложений разрешать его на основе указанных вами параметров.Обратите внимание: поскольку сборка не загружена в ваш основной домен приложений, этот тип недоступен из вашего метода Main.Ваш Lib.Test должен быть производным от MarshalByRefObject, чтобы система маршаллинга могла создать прокси-сервер (который в дальнейшем будет преобразован в динамический прокси-сервер при назначении ему динамического.)


РЕДАКТИРОВАТЬ:

После дальнейших размышлений я подозреваю, что проблема заключается в том, что для вызова метода на динамическом прокси он должен отразить объект (который сам является прозрачным прокси для экземпляра в другом вашем AppDomain).) Если он в конечном итоге отражает исходный тип класса (а не «скрытый» прозрачный тип прокси-сервера), это заставит его загрузить копию сборки в локальном домене приложений (таким образом, заблокировав его). Это одна из причин, почемупри использовании изоляции AppDomain вы обычно приводите объект к интерфейсу, определенному в отдельной сборке, на которую могут ссылаться как основное приложение, так и размещенный домен AppDomain.Каждому из них будет загружена собственная копия сборки интерфейса, но теперь сборка «реализации» изолирована.

0 голосов
/ 27 июня 2011

У вас есть два варианта, вам нужно найти имя сборки перед запуском и указать его жестко, или, если вы не знаете, перед запуском, вам нужно написать вторую библиотеку, которую вы знаете FullName и загрузите это в AppDomain. Вторая библиотека будет одним классом с одной функцией

public Assembly GetAssemblyForOtherAppDomain(string path) 
{ 
    return Assembly.LoadFile(path) 
}

Это должно загрузить вашу цель в новый домен приложений, не блокируя его, как это должно открыть ее с теневой копией.

РЕДАКТИРОВАТЬ: почему ваш метод не сработал, вы правы в том, что загрузка блокирует его, и после загрузки сборки в домен приложений она не может быть выгружена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...