Не могу найти способ удалить / перезапустить состояние DLL в памяти из моей службы Windows - PullRequest
2 голосов
/ 22 ноября 2011

Я использую стороннюю DLL, которая читает файл при первом его использовании, но никогда не проверяет его на наличие изменений. Моя идея состояла в том, чтобы просто загрузить DLL в AppDomain и выгрузить DLL после того, как я сделаю свой первый вызов - поэтому я стираю состояние DLL при каждом вызове (более или менее).

AssemblyName name = AssemblyName.GetAssemblyName(@"C:\fake.dll");
AppDomain newDomain = AppDomain.CreateDomain("DomainName");
Assembly lib = newDomain.Load(name);

...
//Use the Assembly

AppDomain.Unload(newDomain);

Этот блок кода может быть запущен несколько раз в секунду - неэффективно, но пока это мой единственный вариант с этой DLL ...

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

Я не понимаю AppDomain или я должен атаковать это под другим углом?

Редактировать : Проблема загрузки DLL в мой собственный домен была решена с помощью класса MarshalByRefObject (спасибо!), Но я не хочу, чтобы он был междоменным. Я хочу, чтобы эта DLL жила и умирала в этом одном домене приложений - будет ли достаточно метода Unload, чтобы разбить все надежды на то, что состояние этой библиотеки DLL появится в другом домене приложений?

Ответы [ 3 ]

3 голосов
/ 22 ноября 2011

Эта строка:

Assembly lib = newDomain.Load(name);

заставляет сборку также загружаться в current AppDomain , поскольку класс Assembly помечен как [Serializable], а не MarshalByRefObject, и поэтому сериализуется по Граница домена приложения:

Вы можете создать свой собственный объект MarshalByRefObject для передачи вызовов в другую сборку. См. Пример в MSDN для получения дополнительной информации. Но основная идея примерно такая:

public class Worker : MarshalByRefObject, IWorker
{
    public void DoWork() 
    { 
        // Load the assembly here. This code will run in the AppDomain
    }
}

public interface IWorker
{
    void DoWork();
}


public class Program
{
    public static void Main()
    {
        AppDomain ad = AppDomain.CreateDomain("New domain");

        // This line creates a proxy to your worker.
        IWorker remoteWorker = (IWorker) ad.CreateInstanceAndUnwrap(
            Assembly.GetExecutingAssembly().FullName,
            "Worker");

        remoteWorker.DoWork();

        ad.Unload();
    }
}

Вы даже можете пойти дальше и сделать так, чтобы ваш класс Worker реализовал интерфейс и поместил его в общую сборку.

3 голосов
/ 22 ноября 2011

Если вы непосредственно используете объекты из библиотеки DLL в своем коде "// Использовать сборку", то вы перетащили библиотеку DLL в текущий домен приложения, а также в новый.Это означает, что вы на самом деле не достигли своей цели.

Вам нужно будет использовать отражение, чтобы использовать классы и методы, загруженные в новый домен приложений, без вытягивания библиотеки DLL в исходный домен приложений.

1 голос
/ 22 ноября 2011

Не уверен, что происходит в разделе //Use the Assembly здесь, но я подозреваю, что вы случайно загружаете сборку в , вызывающий AppDomain, например, appDomain вашего основного приложения.

То, что вы хотите сделать, это поместить весь код, который использует эту DLL, в сборку самостоятельно, в идеале с очень простым методом класса, унаследованного от MarshalByRefObject, чтобы запустить его, например:

public class StartErUp : MarshalByRefObject {
    public void RunThatOtherDll() { ... }
}

затем загрузите этот класс с помощью AppDomain.CreateInstanceAndUnwrap ().Важно, чтобы ваш класс наследовал от MarshalByRefObject, потому что это говорит CLR создать для него прокси-сервер между приложениями, а не пытаться сериализовать (копировать) его через домены приложений.

...