2009-09-03 8 views
9

Krótkie wyjaśnienie, dlaczego chcę, aby to zrobić:Czy mogę ustawić domyślną AppDomain przy użyciu kopii w tle niektórych złożeń?

Jestem zajęty pisanie plugin dla Autodesk Revit Architecture 2010. Testowanie mój kod wtyczki jest wyjątkowo kłopotliwe, bo trzeba ponownie uruchomić Autodesk dla każdej sesji debugowania, ręcznie załadować projekt Revit, kliknij kartę Dodatki, a następnie uruchom moją wtyczkę. To trwa zbyt długo.

Napisałem drugą wtyczkę, która obsługuje tłumacza IronPythona. W ten sposób mogę grać z API dostarczonym przez Revit. Ale ostatecznie, kod musi zostać przepisany w C# - i debugowany.

Łatwo, pomyślałem: wystarczy załadować bibliotekę DLL wtyczek ze skryptu IronPython i wykonać ją. To działa, ale po załadowaniu nie mogę dokonać rekompilacji w Visual Studio, ponieważ biblioteka DLL jest teraz ładowana do Revit AppDomain.

Łatwo, pomyślałem (z niewielką pomocą StackOverflow): Wystarczy załadować bibliotekę DLL do nowej AppDomain. Niestety obiekty RevitAPI nie mogą zostać przekazane do innej domeny AppDomain, ponieważ nie rozszerzają zakresu MarshalByRefObject.

Myślę, że mogę być na czymś w kopiach w tle. Wydaje się, że ASP.NET to robi. Ale czytając dokumentację na MSDN, wydaje mi się, że mogę to tylko określić, gdy tworzy AppDomain.

Czy mogę to zmienić dla bieżącego (domyślnie) AppDomain? Czy mogę zmusić go do korzystania z kopii w tle bibliotek DLL z określonego katalogu?

Odpowiedz

5

Nie wiem, co próbujesz zrobić, ale istnieją pewne nieaktualne metody włączania ShadowCopy w bieżącym AppDomain.

AppDomain.CurrentDomain.SetCachePath(@"C:\Cache"); 
AppDomain.CurrentDomain.SetShadowCopyPath(AppDomain.CurrentDomain.BaseDirectory); 
AppDomain.CurrentDomain.SetShadowCopyFiles(); 
+0

Dokumenty mówią, że są przestarzałe - czy to jest to samo, co przestarzałe? Dam temu szansę. Dzięki! –

+0

Nie mogę go uruchomić ... –

+1

To działa dla mnie. Zmieniłem moją odpowiedź na działający przykład. Skopiuj i wklej go do swojej metody Main().Upewnij się również, że twoja metoda Main() nie odwołuje się bezpośrednio do twoich innych zespołów, ponieważ .NET załaduje je, zanim 'SetShadowCopyFiles()' zostanie nazwane –

2

Czasami nie jest możliwe, aby zmodyfikować main() kod metody, ponieważ, na przykład, piszesz plug-in i to instancja przez kierownika.

W takim przypadku proponuję skopiować zespół i pdb (i te zależne w zdarzeniu AssemblyResolve) do lokalizacji tymczasowej i załadować je stamtąd z Assembly.LoadFile() (nie LoadFrom()).

Zalety: - brak blokowania dll. - za każdym razem, gdy zestaw docelowy jest rekompilowany, uzyskujesz dostęp do nowej wersji (właśnie dlatego .LoadFile()). - cały zestaw jest w pełni dostępny w AppDomain.CurrentDomain.

Minusy: - konieczne jest kopiowanie plików. - zespołów nie można rozładować, a to może być niewygodne, ponieważ zasoby nie są zwalniane.

Pozdrawiam,

PD: Ten kod wykonuje pracę.

/// <summary> 
/// Loads an assembly without locking the file 
/// Note: the assemblys are loaded in current domain, so they are not unloaded by this class 
/// </summary> 
public class AssemblyLoader : IDisposable 
{ 
    private string _assemblyLocation; 
    private string _workingDirectory; 
    private bool _resolveEventAssigned = false; 

    /// <summary> 
    /// Creates a copy in a new temp directory and loads the copied assembly and pdb (if existent) and the same for referenced ones. 
    /// Does not lock the given assembly nor pdb and always returns new assembly if recopiled. 
    /// Note: uses Assembly.LoadFile() 
    /// </summary> 
    /// <param name="assemblyOriginalPath"></param> 
    /// <returns></returns> 
    public Assembly LoadFileCopy(string assemblyLocation) 
    { 
     lock (this) 
     { 
      _assemblyLocation = assemblyLocation; 

      if (!_resolveEventAssigned) 
      { 
       _resolveEventAssigned = true; 

       AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyFileCopyResolveEvent); 
      } 

      // Create new temp directory 
      _workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 
      Directory.CreateDirectory(_workingDirectory); 

      // Generate copy 
      string assemblyCopyPath = Path.Combine(_workingDirectory, Path.GetFileName(_assemblyLocation)); 
      System.IO.File.Copy(_assemblyLocation, assemblyCopyPath, true); 

      // Generate copy of referenced assembly debug info (if existent) 
      string assemblyPdbPath = _assemblyLocation.Replace(".dll", ".pdb"); 
      if (File.Exists(assemblyPdbPath)) 
      { 
       string assemblyPdbCopyPath = Path.Combine(_workingDirectory, Path.GetFileName(assemblyPdbPath)); 
       System.IO.File.Copy(assemblyPdbPath, assemblyPdbCopyPath, true); 
      } 

      // Use LoadFile and not LoadFrom. LoadFile allows to load multiple copies of the same assembly 
      return Assembly.LoadFile(assemblyCopyPath); 
     } 
    } 

    /// <summary> 
    /// Creates a new copy of the assembly to resolve and loads it 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="args"></param> 
    /// <returns></returns> 
    private Assembly AssemblyFileCopyResolveEvent(object sender, ResolveEventArgs args) 
    { 
     string referencedAssemblyFileNameWithoutExtension = System.IO.Path.GetFileName(args.Name.Split(',')[0]); 

     // Generate copy of referenced assembly 
     string referencedAssemblyPath = Path.Combine(Path.GetDirectoryName(_assemblyLocation), referencedAssemblyFileNameWithoutExtension + ".dll"); 
     string referencedAssemblyCopyPath = Path.Combine(Path.GetDirectoryName(args.RequestingAssembly.Location), referencedAssemblyFileNameWithoutExtension + ".dll"); 
     System.IO.File.Copy(referencedAssemblyPath, referencedAssemblyCopyPath, true); 

     // Generate copy of referenced assembly debug info (if existent) 
     string referencedAssemblyPdbPath = Path.Combine(Path.GetDirectoryName(_assemblyLocation), referencedAssemblyFileNameWithoutExtension + ".pdb"); 
     if (File.Exists(referencedAssemblyPdbPath)) 
     { 
      string referencedAssemblyPdbCopyPath = Path.Combine(Path.GetDirectoryName(args.RequestingAssembly.Location), referencedAssemblyFileNameWithoutExtension + ".pdb"); 
      System.IO.File.Copy(referencedAssemblyPath, referencedAssemblyCopyPath, true); 
     } 

     // Use LoadFile and not LoadFrom. LoadFile allows to load multiple copies of the same assembly 
     return Assembly.LoadFile(referencedAssemblyCopyPath); 
    } 


    public void Dispose() 
    { 
     Dispose(true); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      if (_resolveEventAssigned) 
      { 
       AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(AssemblyFileCopyResolveEvent); 

       _resolveEventAssigned = false; 
      } 
     } 
    } 
} 
+0

Dzięki. W zasadzie używam tej techniki tutaj: http://code.google.com/p/revitpythonshell/wiki/FeaturedScriptLoadplugin –

+0

Problem związany z techniką, do której się odnosisz, polega na tym, że rekompilujesz zespół, do którego odwołuje się główny zestaw, oraz już go wczytałeś, ten zbiór referencyjny nie jest ponownie ładowany (zaktualizowany). Na przykład. ładujesz zespół o nazwie A, który zależy od innego zestawu o nazwie B. –

+1

Np .: 1) ładujesz zespół o nazwie A, który zawiera typ A1, który używa innego typu B1, który znajduje się na innym zestawie o nazwie B (zespół odwołania do zespołu A B). 2) bez wyłączania domeny aplikacji (bez zamykania aplikacji), dodajesz nowy typ B2 do zespołu B i referencję B2 z typu A1 z zespołu A. 3) ładujesz ponownie: tutaj nowy typ B2 może można znaleźć błąd, ponieważ, po raz drugi, .Net nie rozwiązuje ponownie zespołu B (został on rozwiązany tylko raz w kroku 1). Nie wiem, czy byłem wystarczająco jasny. Pozdrawiam, –

1

Jest teraz plugin Revit dla dynamicznie załadunku/rozładunku inne Revit wtyczek, dzięki czemu można zmienić, rekompilacji i testy bez konieczności ponownego otwarcia Revit Project. Znalazłem go na Building Coder blog. Pochodzi z Revit SDK.

+0

dziękuję, znam zarówno bloga, jak i AddInManager. To naprawdę działa! (z wyjątkiem, jak się wydaje, dla formularzy WPF XAML, ale to już inna sprawa, nie będę kłopotał się po FTM) –

Powiązane problemy