Udostępnij za pośrednictwem


Upraszczanie wdrażania i rozwiązywania problemów z biblioteką DLL z .NET Framework

 

Steven Pratschner
Microsoft Corporation

Zaktualizowano listopad 2001 r.

Krótki opis: W tym artykule przedstawiono koncepcję zestawu i opisano sposób, w jaki .NET Framework używa zestawów do rozwiązywania problemów z wersją i wdrażaniem. (16 drukowanych stron)

Zawartość

Wprowadzenie
Opis problemu
Cechy rozwiązania
Zestawy: bloki konstrukcyjne
Przechowywanie wersji i udostępnianie
Zasady wersji
Wdrożenie
Podsumowanie

Wprowadzenie

Firma Microsoft® .NET Framework wprowadza kilka nowych funkcji mających na celu uproszczenie wdrażania aplikacji i rozwiązywania problemów z biblioteką DLL Hell. Zarówno użytkownicy końcowi, jak i deweloperzy znają problemy z przechowywaniem wersji i wdrażaniem, które mogą wystąpić w dzisiejszych systemach opartych na składnikach. Na przykład praktycznie każdy użytkownik końcowy zainstalował nową aplikację na swojej maszynie, tylko w celu znalezienia, że istniejąca aplikacja tajemniczo przestaje działać. Większość deweloperów spędziła również czas z regeditem, starając się zachować wszystkie niezbędne wpisy rejestru spójne w celu aktywowania klasy COM.

Wytyczne projektowe i techniki implementacji używane w .NET Framework do rozwiązywania bibliotek DLL Hell są oparte na pracy wykonanej w systemie Microsoft Windows® 2000, zgodnie z opisem Rick Anderson w The End of DLL Hell, i David D'Souza, BJ Whalen i Peter Wilson w implementowaniu współużytkowania składników side-by side w aplikacjach (rozszerzone). .NET Framework rozszerza tę poprzednią pracę, udostępniając funkcje, w tym izolację aplikacji i składniki równoległe dla aplikacji utworzonych przy użyciu kodu zarządzanego na platformie .NET. Należy również pamiętać, że system Windows XP udostępnia te same funkcje izolacji i przechowywania wersji dla kodu niezarządzanego, w tym klasy COM i biblioteki DLL Win32 (zobacz How To Build and Service Isolated Applications and Service Isolated Applications and Side-by-Side Assemblies for Windows XP (Jak tworzyć i obsługiwać izolowane aplikacje oraz zestawy równoległe dla systemu Windows XP).

W tym artykule przedstawiono koncepcję zestawu i opisano sposób, w jaki platforma .NET używa zestawów do rozwiązywania problemów z wersją i wdrażaniem. W szczególności omówimy, w jaki sposób zestawy są ustrukturyzowane, jak są nazwane, oraz jak kompilatory i środowisko uruchomieniowe języka wspólnego (CLR) używają zestawów do rejestrowania i wymuszania zależności wersji między elementami aplikacji. Omówimy również, w jaki sposób aplikacje i administratorzy mogą dostosowywać zachowanie obsługi wersji za pomocą zasad wersji.

Po wprowadzeniu i opisie zestawów zostanie przedstawionych kilka scenariuszy wdrażania, zapewniając próbkowanie różnych opcji pakowania i dystrybucji dostępnych w .NET Framework.

Opis problemu

Przechowywanie wersji

Z perspektywy klienta najczęstszym problemem z przechowywaniem wersji jest to, co nazywamy biblioteką DLL Hell. Po prostu stwierdzono, biblioteka DLL Hell odnosi się do zestawu problemów spowodowanych, gdy wiele aplikacji próbuje współużytkować wspólny składnik, taki jak biblioteka DLL (dynamic-link library) lub klasa Modelu obiektów składników (COM). W najbardziej typowym przypadku jedna aplikacja zainstaluje nową wersję udostępnionego składnika, która nie jest zgodna z poprzednimi wersjami już na maszynie. Mimo że aplikacja, która została właśnie zainstalowana, działa prawidłowo, istniejące aplikacje zależne od poprzedniej wersji składnika udostępnionego mogą już nie działać. W niektórych przypadkach przyczyna problemu jest jeszcze bardziej subtelna. Rozważmy na przykład scenariusz, w którym użytkownik pobiera kontrolkę Microsoft ActiveX® jako efekt uboczny wizyty w witrynie sieci Web. Po pobraniu kontrolki zastąpi wszystkie istniejące wersje kontrolki, które były obecne na maszynie. Jeśli aplikacja zainstalowana na maszynie korzysta z tej kontrolki, może też przestać działać.

W wielu przypadkach istnieje znaczne opóźnienie, zanim użytkownik wykryje, że aplikacja przestała działać. W związku z tym często trudno jest pamiętać, kiedy wprowadzono zmianę na maszynie, która mogła mieć wpływ na aplikację. Użytkownik może pamiętać o zainstalowaniu czegoś tydzień temu, ale nie ma oczywistej korelacji między instalacją a zachowaniem, które teraz widzą. Co gorsza, istnieje kilka narzędzi diagnostycznych dostępnych obecnie, aby pomóc użytkownikowi (lub osobie pomocy technicznej, która im pomaga) określić, co jest złe.

Przyczyną tych problemów jest to, że informacje o wersji różnych składników aplikacji nie są rejestrowane ani wymuszane przez system. Ponadto zmiany wprowadzone w systemie w imieniu jednej aplikacji zwykle wpływają na wszystkie aplikacje na maszynie — tworzenie aplikacji, która jest obecnie całkowicie odizolowana od zmian, nie jest łatwa.

Jednym z powodów, dla których trudno jest skompilować izolowane aplikacje, jest to, że bieżące środowisko uruchomieniowe zwykle zezwala na instalację tylko jednej wersji składnika lub aplikacji. To ograniczenie oznacza, że autorzy składników muszą napisać kod w sposób, który pozostaje zgodny z poprzednimi wersjami, w przeciwnym razie ryzykują zerwanie istniejących aplikacji podczas instalowania nowego składnika. W praktyce pisanie kodu, który jest na zawsze zgodny z poprzednimi wersjami, jest niezwykle trudne, jeśli nie jest niemożliwe. Na platformie .NET pojęcie obok siebie jest podstawą scenariusza przechowywania wersji. Obok siebie jest możliwość instalowania i uruchamiania wielu wersji tego samego składnika na maszynie w tym samym czasie. W przypadku składników, które obsługują równolegle, autorzy nie muszą być związani z zachowaniem ścisłej zgodności z poprzednimi wersjami, ponieważ różne aplikacje mogą korzystać z różnych wersji składnika udostępnionego.

Wdrażanie i instalacja

Obecnie instalowanie aplikacji jest procesem wieloetapowym. Zazwyczaj instalowanie aplikacji polega na kopiowaniu wielu składników oprogramowania na dysk i tworzeniu serii wpisów rejestru opisujących te składniki systemu.

Rozdzielenie wpisów w rejestrze i plików na dysku sprawia, że bardzo trudno jest replikować aplikacje i odinstalować je. Ponadto relacja między różnymi wpisami wymaganymi do pełnego opisania klasy COM w rejestrze jest bardzo luźna. Te wpisy często zawierają wpisy dla coclasses, interfejsów, bibliotek typów i identyfikatorów aplikacji DCOM, nie wspominając o żadnych wpisach wykonanych w celu rejestrowania rozszerzeń dokumentów lub kategorii składników. Często kończy się to na ręcznym synchronizowaniu tych danych.

Na koniec ten ślad rejestru jest wymagany do aktywowania dowolnej klasy COM. Znacznie komplikuje to proces wdrażania aplikacji rozproszonych, ponieważ każda maszyna kliencka musi zostać dotknięta w celu utworzenia odpowiednich wpisów rejestru.

Te problemy są spowodowane przede wszystkim opisem składnika, który jest oddzielony od samego składnika. Innymi słowy, aplikacje nie opisują się samodzielnie ani nie są samodzielne.

Cechy rozwiązania

.NET Framework musi zapewnić następujące podstawowe możliwości w celu rozwiązania właśnie opisanych problemów:

  • Aplikacje muszą być samoopisujące. Aplikacje, które samodzielnie opisują, usuwają zależność od rejestru, umożliwiając instalację bez wpływu i upraszczając odinstalowywanie i replikację.
  • Informacje o wersji muszą być rejestrowane i wymuszane. Obsługa wersji musi być wbudowana w platformę, aby zapewnić załadowanie odpowiedniej wersji zależności w czasie wykonywania.
  • Musi pamiętać "ostatnie znane dobre". Po pomyślnym uruchomieniu aplikacji platforma musi pamiętać zestaw składników — w tym ich wersje — które współdziałały ze sobą. Ponadto należy podać narzędzia, które umożliwiają administratorom łatwe przywracanie aplikacji do tego stanu "ostatniego znanego dobrego".
  • Obsługa składników równoległych. Zezwalanie na zainstalowanie i uruchomienie wielu wersji składnika na maszynie jednocześnie umożliwia obiektom wywołującym określenie, która wersja ma zostać załadowana zamiast wersji "wymuszonej" na nieświadomie. .NET Framework jest obok siebie krok dalej, pozwalając wielu wersji samej struktury współistnieć na jednej maszynie. Znacznie upraszcza to proces uaktualniania, ponieważ administrator może w razie potrzeby uruchamiać różne aplikacje w różnych wersjach .NET Framework.
  • Izolacja aplikacji. .NET Framework musi ułatwić pisanie aplikacji, które nie mogą mieć wpływu na zmiany wprowadzone na maszynie w imieniu innych aplikacji.

Zestawy: bloki konstrukcyjne

Zestawy to bloki konstrukcyjne używane przez .NET Framework do rozwiązywania właśnie opisanych problemów z przechowywaniem wersji i wdrażaniem. Zestawy to jednostka wdrażania typów i zasobów. Na wiele sposobów zestaw równa się biblioteki DLL w dzisiejszym świecie; w istocie zestawy są "logicznymi bibliotekami DLL".

Zestawy są samoopisujące się za pomocą metadanych nazywanych manifestem. Podobnie jak platforma .NET używa metadanych do opisywania typów, używa również metadanych do opisywania zestawów zawierających typy.

Zestawy są o wiele więcej niż wdrożenie. Na przykład przechowywanie wersji na platformie .NET odbywa się na poziomie zestawu — wersja modułu lub typu nie jest mniejsza. Ponadto zestawy są używane do udostępniania kodu między aplikacjami. Zestaw zawarty w typie jest częścią tożsamości typu.

System zabezpieczeń dostępu do kodu używa zestawów w rdzeniu modelu uprawnień. Autor rekordów zestawu w manifeście zestaw uprawnień wymaganych do uruchomienia kodu, a administrator przyznaje uprawnienia do kodu na podstawie zestawu, w którym znajduje się kod.

Na koniec zestawy są również podstawowe dla systemu typów i systemu czasu wykonywania, w których ustanawiają granicę widoczności dla typów i służą jako zakres czasu wykonywania do rozpoznawania odwołań do typów.

Manifesty zestawów

W szczególności manifest zawiera następujące dane dotyczące zestawu:

  • Tożsamości. Tożsamość zestawu składa się z czterech części: prostej nazwy tekstowej, numeru wersji, opcjonalnej kultury i opcjonalnego klucza publicznego, jeśli zestaw został utworzony do udostępniania (zobacz sekcję w temacie Udostępnione zestawy poniżej).
  • Lista plików. Manifest zawiera listę wszystkich plików tworzących zestaw. Dla każdego pliku manifest rejestruje jego nazwę i skrót kryptograficzny jego zawartości w momencie skompilowania manifestu. Ten skrót jest weryfikowany w czasie wykonywania, aby upewnić się, że jednostka wdrażania jest spójna.
  • Odwołania do zestawów. Zależności między zestawami są przechowywane w manifeście wywołującego zestawu. Informacje o zależności zawierają numer wersji, który jest używany w czasie wykonywania, aby upewnić się, że załadowana jest poprawna wersja zależności.
  • Wyeksportowane typy i zasoby. Opcje widoczności dostępne dla typów i zasobów obejmują "widoczne tylko w moim zestawie" i "widoczne dla obiektów wywołujących poza moim zestawem".
  • Żądania uprawnień. Żądania uprawnień dla zestawu są pogrupowane w trzy zestawy: 1) wymagane do uruchomienia zestawu, 2) te, które są wymagane, ale zestaw nadal będzie miał pewne funkcje, nawet jeśli nie zostaną przyznane, i 3) tych, których autor nigdy nie chce, aby zestaw został przyznany.

Narzędzie SDK dezasemblatora IL (Ildasm) jest przydatne do przeglądania kodu i metadanych w zestawie. Rysunek 1 to przykładowy manifest wyświetlany przez Ildasm. Dyrektywa .assembly identyfikuje zestaw i dyrektywy extern .assembly zawierają informacje o innych zestawach, od których zależy.

Rysunek 1. Przykładowy manifest wyświetlany przez dezasembler IL

Struktura zestawu

Do tej pory zestawy zostały opisane przede wszystkim jako koncepcja logiczna. W tej sekcji zestawy są bardziej konkretne, opisując, jak są reprezentowane fizycznie.

Ogólnie rzecz biorąc, zestawy składają się z czterech elementów: metadanych zestawu (manifest), metadanych opisujących typy, kodu języka pośredniego (IL), który implementuje typy i zestaw zasobów. Nie wszystkie z nich są obecne w każdym zestawie. Tylko manifest jest ściśle wymagany, ale typy lub zasoby są potrzebne, aby zapewnić zestawowi dowolną zrozumiałą funkcjonalność.

Istnieje kilka opcji tworzenia pakietów tych czterech elementów. Na przykład rysunek 2 przedstawia pojedynczą bibliotekę DLL zawierającą cały zestaw: manifest, metadane typu, kod IL i zasoby.

Rysunek 2. Biblioteka DLL zawierająca wszystkie elementy zestawu

Alternatywnie zawartość zestawu może być rozłożona na wiele plików. Na rysunku 3 autor zdecydował się oddzielić kod narzędzia do innej biblioteki DLL i zachować duży plik zasobów (w tym przypadku JPEG) w oryginalnym pliku. Jednym z powodów, dla których można to zrobić, jest zoptymalizowanie pobierania kodu. .NET Framework pobierze plik tylko wtedy, gdy jest przywoływane, więc jeśli zestaw zawiera kod lub zasoby, do których uzyskuje się dostęp rzadko, podzielenie ich na poszczególne pliki zwiększy wydajność pobierania. Innym typowym scenariuszem, w którym jest używanych wiele plików, jest utworzenie zestawu składającego się z kodu z więcej niż jednego języka. W takim przypadku należy utworzyć oddzielnie każdy plik (moduł), a następnie pogrupować je w zestaw przy użyciu narzędzia Konsolidator zestawów udostępnionego w zestawie SDK .NET Framework (al.exe).

Rysunek 3. Elementy zestawu rozłożone na wiele plików

Przechowywanie wersji i udostępnianie

Jedną z głównych przyczyn hell biblioteki DLL jest model udostępniania używany obecnie w systemach opartych na składnikach. Domyślnie poszczególne składniki oprogramowania są współużytkowane przez wiele aplikacji na maszynie. Na przykład za każdym razem, gdy program instalacyjny kopiuje bibliotekę DLL do katalogu systemowego lub rejestruje klasę w rejestrze COM, kod ten może mieć wpływ na inne aplikacje uruchomione na maszynie. W szczególności, jeśli istniejąca aplikacja używa poprzedniej wersji tego składnika udostępnionego, ta aplikacja automatycznie rozpocznie korzystanie z nowej wersji. Jeśli składnik udostępniony jest ściśle zgodny z poprzednimi wersjami, może to być w porządku, ale w wielu przypadkach utrzymywanie zgodności z poprzednimi wersjami jest trudne, jeśli nie jest niemożliwe. Jeśli zgodność z poprzednimi wersjami nie jest zachowywana lub nie można jej zachować, często powoduje to uszkodzenie aplikacji, które są uszkodzone jako efekt uboczny innych aplikacji instalowanych.

Podstawowa wytyczna projektowania na platformie .NET to wyizolowane składniki (lub zestawy). Izolowanie zestawu oznacza, że dostęp do zestawu może uzyskać tylko jedna aplikacja — nie jest on współużytkowany przez wiele aplikacji na maszynie i nie może mieć wpływu na zmiany wprowadzone w systemie przez inne aplikacje. Izolacja zapewnia deweloperowi absolutną kontrolę nad kodem używanym przez jego aplikację. Zestawy izolowane lub prywatne aplikacje są domyślne w aplikacjach platformy .NET. Trend w kierunku izolowanych składników rozpoczął się w systemie Microsoft Windows 2000 wraz z wprowadzeniem pliku lokalnego. Ten plik został użyty do wywołania zarówno modułu ładującego systemu operacyjnego, jak i modelu COM, aby najpierw wyszukać w katalogu aplikacji podczas próby zlokalizowania żądanego składnika. (Zapoznaj się z powiązanym artykułem w bibliotece MSDN Implementowanie współużytkowania składników równoległych w aplikacjach).

Istnieją jednak przypadki, w których konieczne jest współużytkowanie zestawu między aplikacjami. Oczywiście nie miałoby sensu, aby każda aplikacja miała własną kopię system.Windowns.Forms, System.Web lub wspólną kontrolkę Web Forms.

Na platformie .NET udostępnianie kodu między aplikacjami jest jawną decyzją. Zestawy, które są współużytkowane, mają pewne dodatkowe wymagania. W szczególności współużytkowane zestawy powinny obsługiwać równocześnie, aby można było zainstalować i uruchomić wiele wersji tego samego zestawu na tym samym komputerze, a nawet w ramach tego samego procesu w tym samym czasie. Ponadto zestawy udostępnione mają bardziej rygorystyczne wymagania dotyczące nazewnictwa. Na przykład udostępniony zestaw musi mieć nazwę, która jest globalnie unikatowa.

Potrzeba zarówno izolacji, jak i dzielenia się prowadzi nas do myślenia o dwóch "rodzajach" zestawów. Jest to dość luźna kategoryzacja w tym, że nie ma rzeczywistych różnic strukturalnych między nimi, ale raczej różnica polega na tym, jak będą one używane: czy prywatne dla jednej aplikacji, czy współdzielone między wieloma.

zestawy Application-Private

Zestaw prywatny aplikacji to zestaw, który jest widoczny tylko dla jednej aplikacji. Oczekujemy, że będzie to najczęstszy przypadek na platformie .NET. Wymagania dotyczące nazewnictwa zestawów prywatnych są proste: nazwy zestawów muszą być unikatowe tylko w aplikacji. Nie ma potrzeby globalnej unikatowej nazwy. Zachowanie unikatowych nazw nie jest problemem, ponieważ deweloper aplikacji ma pełną kontrolę nad tym, które zestawy są izolowane do aplikacji.

Zestawy prywatne aplikacji są wdrażane w strukturze katalogów aplikacji, w której są używane. Zestawy prywatne można umieścić bezpośrednio w katalogu aplikacji lub w jego podkatalogu. CLR znajduje te zestawy za pośrednictwem procesu nazywanego sondowaniem. Sondowanie to po prostu mapowanie nazwy zestawu na nazwę pliku zawierającego manifest.

W szczególności clR przyjmuje nazwę zestawu zarejestrowanego w odwołaniu do zestawu, dołącza ".dll" i szuka tego pliku w katalogu aplikacji. W tym schemacie istnieje kilka wariantów, w których środowisko uruchomieniowe będzie szukać w podkatalogach nazwanych przez zestaw lub w podkatalogach nazwanych przez kulturę zestawu. Na przykład deweloper może zdecydować się na wdrożenie zestawu zawierającego zasoby zlokalizowane w języku niemieckim w podkatalogu o nazwie "de" i w języku hiszpańskim w katalogu o nazwie "es". (Aby uzyskać szczegółowe informacje, zobacz przewodnik .NET Framework SDK).

Tak jak opisano, każdy manifest zestawu zawiera informacje o wersji dotyczące jego zależności. Te informacje o wersji nie są wymuszane dla zestawów prywatnych, ponieważ deweloper ma pełną kontrolę nad zestawami wdrożonym w katalogu aplikacji.

Zestawy udostępnione

.NET Framework obsługuje również koncepcję zestawu współużytkowanego. Zestaw udostępniony jest taki, który jest używany przez wiele aplikacji na maszynie. W przypadku platformy .NET udostępnianie kodu między aplikacjami jest jawną decyzją. Zestawy udostępnione mają pewne dodatkowe wymagania mające na celu uniknięcie problemów z udostępnianiem, które występują obecnie. Oprócz obsługi równoległego opisu opisanego wcześniej współużytkowane zestawy mają znacznie bardziej rygorystyczne wymagania dotyczące nazewnictwa. Na przykład zestaw udostępniony musi mieć nazwę, która jest globalnie unikatowa. Ponadto system musi zapewnić "ochronę nazwy", czyli uniemożliwianie ponownemu użyciu nazwy zestawu innego użytkownika. Załóżmy na przykład, że jesteś dostawcą kontrolki siatki i wydaliśmy wersję 1 zestawu. Jako autor musisz mieć pewność, że nikt inny nie może zwolnić zestawu, który twierdzi, że jest w wersji 2 lub kontrolki siatki. .NET Framework obsługuje te wymagania dotyczące nazewnictwa za pomocą techniki nazywanej silnymi nazwami (opisano szczegółowo w następnej sekcji).

Zazwyczaj autor aplikacji nie ma takiej samej kontroli nad udostępnionymi zestawami używanymi przez aplikację. W związku z tym informacje o wersji są sprawdzane przy każdym odwołaniu do zestawu udostępnionego. Ponadto .NET Framework umożliwia aplikacjom i administratorom zastępowanie wersji zestawu używanego przez aplikację przez określenie zasad wersji.

Zestawy udostępnione nie muszą być wdrażane prywatnie w jednej aplikacji, chociaż takie podejście jest nadal możliwe, zwłaszcza jeśli wdrożenie xcopy jest wymagane. Oprócz katalogu aplikacji prywatnej zestaw udostępniony może być również wdrożony w globalnej pamięci podręcznej zestawów lub w dowolnym adresie URL, o ile baza kodu opisująca lokalizację zestawu jest dostarczana w pliku konfiguracji aplikacji. Globalna pamięć podręczna zestawów to magazyn obejmujący całą maszynę dla zestawów, które są używane przez więcej niż jedną aplikację. Jak opisano, wdrażanie w pamięci podręcznej nie jest wymagane, ale ma pewne zalety. Na przykład magazyn równoległy wielu wersji zestawu jest dostarczany automatycznie. Ponadto administratorzy mogą używać magazynu do wdrażania poprawek usterek lub poprawek zabezpieczeń, które mają być używane przez każdą aplikację na maszynie. Na koniec istnieje kilka ulepszeń wydajności związanych z wdrażaniem w globalnej pamięci podręcznej zestawów. Pierwszy polega na weryfikacji podpisów silnych nazw zgodnie z opisem w sekcji Strong Name poniżej. Druga poprawa wydajności obejmuje zestaw roboczy. Jeśli kilka aplikacji używa tego samego zestawu jednocześnie, ładowanie tego zestawu z tej samej lokalizacji na dysku wykorzystuje zachowanie współużytkowania kodu zapewniane przez system operacyjny. Natomiast załadowanie tego samego zestawu z wielu różnych lokalizacji (katalogów aplikacji) spowoduje załadowanie wielu kopii tego samego kodu. Dodanie zestawu do pamięci podręcznej na komputerze użytkownika końcowego jest zazwyczaj realizowane przy użyciu programu instalacyjnego opartego na Instalatorze Windows lub innej technologii instalacji. Zestawy nigdy nie kończą się w pamięci podręcznej jako efekt uboczny uruchamiania niektórych aplikacji lub przechodzenia do strony internetowej. Zamiast tego zainstalowanie zestawu w pamięci podręcznej wymaga jawnej akcji ze strony użytkownika. Instalator Windows 2.0 dostarczany z systemami Windows XP i Visual Studio .NET został rozszerzony w celu pełnego zrozumienia koncepcji zestawów, pamięci podręcznej zestawów i aplikacji izolowanych. Oznacza to, że będzie można używać wszystkich funkcji Instalatora Windows, takich jak instalowanie na żądanie i naprawianie aplikacji, za pomocą aplikacji .NET.

Często nie jest praktyczne tworzenie pakietu instalacyjnego za każdym razem, gdy chcesz dodać zestaw do pamięci podręcznej na maszynach deweloperskich i testowych. W związku z tym zestaw SDK platformy .NET zawiera niektóre narzędzia do pracy z pamięcią podręczną zestawów. Pierwszym z nich jest narzędzie o nazwie gacutil, które umożliwia dodawanie zestawów do pamięci podręcznej i usuwanie ich później. Użyj przełącznika /i, aby dodać zestaw do pamięci podręcznej:

gacutil /i:myassembly.dll 
See the .NET Framework SDK documentation for a full description of the 
      options supported by gacutil.

Inne narzędzia to rozszerzenie powłoki systemu Windows, które umożliwia manipulowanie pamięcią podręczną za pomocą Eksploratora Windows i narzędzia konfiguracji .NET Framework. Dostęp do rozszerzenia powłoki można uzyskać, przechodząc do podkatalogu "assembly" w katalogu systemu Windows. Narzędzie konfiguracji .NET Framework można znaleźć w sekcji Narzędzia administracyjne Panel sterowania.

Rysunek 4 przedstawia widok globalnej pamięci podręcznej zestawów przy użyciu rozszerzenia powłoki.

Rysunek 4. Globalna pamięć podręczna zestawów

Silne nazwy

Silne nazwy służą do włączania bardziej rygorystycznych wymagań dotyczących nazewnictwa skojarzonych z udostępnionymi zestawami. Silne nazwy mają trzy gole:

  • Unikatowość nazw. Udostępnione zestawy muszą mieć nazwy, które są globalnie unikatowe.
  • Zapobiegaj fałszowaniu nazw. Deweloperzy nie chcą, aby ktoś inny wydał kolejną wersję jednego z zestawów i fałszywie twierdzić, że pochodzi od Ciebie, albo przez przypadek, czy celowo.
  • Podaj tożsamość w dokumentacji. Podczas rozpoznawania odwołania do zestawu silne nazwy są używane do zagwarantowania, że zestaw załadowany pochodzi od oczekiwanego wydawcy.

Silne nazwy są implementowane przy użyciu standardowej kryptografii klucza publicznego. Ogólnie rzecz biorąc, proces działa w następujący sposób: Autor zestawu generuje parę kluczy (lub używa istniejącej), podpisuje plik zawierający manifest z kluczem prywatnym i udostępnia klucz publiczny osobom wywołującym. Gdy odwołania są wykonywane do zestawu, obiekt wywołujący rejestruje klucz publiczny odpowiadający kluczowi prywatnemu użytemu do wygenerowania silnej nazwy. Rysunek 5 przedstawia sposób działania tego procesu w czasie programowania, w tym sposób przechowywania kluczy w metadanych i sposobu generowania podpisu.

Scenariusz to zestaw o nazwie "Main", który odwołuje się do zestawu o nazwie "MyLib". MyLib ma nazwę udostępnioną. Ważne kroki zostały opisane w następujący sposób.

Rysunek 5. Proces implementowania nazw udostępnionych

  1. Deweloper wywołuje kompilator przekazujący parę kluczy i zestaw plików źródłowych dla zestawu. Para kluczy jest generowana za pomocą narzędzia zestawu SDK o nazwie SN. Na przykład następujące polecenie generuje nową parę kluczy i zapisuje ją w pliku:

    Sn –k MyKey.snk
    The key pair is passed to the compiler using the custom attribute 
            System.Reflection.AssemblyKeyFileAttribute as follows:
    
       <assembly:AssemblyKeyFileAttribute("TestKey.snk")>
    
  2. Gdy kompilator emituje zestaw, klucz publiczny jest rejestrowany w manifeście w ramach tożsamości zestawu. Uwzględnienie klucza publicznego w ramach tożsamości jest tym, co daje zestawowi globalnie unikatową nazwę.

  3. Po emisji zestawu plik zawierający manifest jest podpisany przy użyciu klucza prywatnego. Wynikowy podpis jest przechowywany w pliku.

  4. Po wygenerowaniu pliku Main przez kompilator klucz publiczny MyLib jest przechowywany w manifeście Main w ramach odwołania do biblioteki MyLib.

W czasie wykonywania istnieją dwa kroki, które .NET Framework należy wykonać, aby upewnić się, że silne nazwy dają deweloperowi wymagane korzyści. Najpierw podpis silnej nazwy MyLib jest weryfikowany tylko wtedy, gdy zestaw jest zainstalowany w globalnej pamięci podręcznej zestawów — podpis nie jest ponownie weryfikowany po załadowaniu pliku przez aplikację. Jeśli zestaw udostępniony nie jest wdrażany w globalnej pamięci podręcznej zestawów, podpis jest weryfikowany za każdym razem, gdy plik zostanie załadowany. Sprawdzenie podpisu gwarantuje, że zawartość biblioteki MyLib nie została zmieniona od czasu skompilowania zestawu. Drugim krokiem jest sprawdzenie, czy klucz publiczny przechowywany w ramach odwołania Main do myLib jest zgodny z kluczem publicznym, który jest częścią tożsamości MyLib. Jeśli te klucze są identyczne, autor narzędzia Main może mieć pewność, że wersja biblioteki MyLib, która została załadowana, pochodzi od tego samego wydawcy, który stworzył wersję biblioteki MyLib, z którą został utworzony program Main. Ta kontrola równoważności klucza jest wykonywana w czasie wykonywania, gdy odwołanie z main do myLib zostanie rozpoznane.

Termin "podpisywanie" często sprawia, że microsoft Authenticode® ma na myśli. Ważne jest, aby zrozumieć, że silne nazwy i Authenticode nie są powiązane w żaden sposób. Te dwie techniki mają różne cele. W szczególności authenticode oznacza poziom zaufania skojarzony z wydawcą, podczas gdy silne nazwy nie. Nie ma certyfikatów ani urzędów podpisywania innych firm skojarzonych z silnymi nazwami. Ponadto podpisywanie silnej nazwy jest często wykonywane przez sam kompilator w ramach procesu kompilacji.

Kolejną kwestią, która warto zauważyć, jest proces "opóźniania podpisywania". Często zdarza się, że autor zestawu nie ma dostępu do klucza prywatnego potrzebnego do pełnego podpisania. Większość firm przechowuje te klucze w dobrze chronionych sklepach, do których można uzyskać dostęp tylko przez kilka osób. W rezultacie .NET Framework udostępnia technikę o nazwie "opóźnianie podpisywania", która umożliwia deweloperowi tworzenie zestawu tylko przy użyciu klucza publicznego. W tym trybie plik nie jest w rzeczywistości podpisany, ponieważ klucz prywatny nie jest dostarczany. Zamiast tego plik jest podpisany później przy użyciu narzędzia SN. Aby uzyskać szczegółowe informacje na temat używania opóźnionego podpisywania zestawu w zestawie SDK .NET Framework, zobacz Temat Opóźnianie podpisywania.

Zasady wersji

Zgodnie z opisem każdy manifest zestawu rejestruje informacje o wersji każdej zależności, względem których została utworzona. Istnieją jednak pewne scenariusze, w których autor aplikacji lub administrator może chcieć uruchomić z inną wersją zależności w czasie wykonywania. Na przykład administratorzy powinni mieć możliwość wdrożenia wersji poprawki błędów bez konieczności ponownego kompilowania każdej aplikacji w celu pobrania poprawki. Ponadto administratorzy muszą mieć możliwość określenia, że określona wersja zestawu nigdy nie jest używana, jeśli zostanie znaleziona dziura zabezpieczeń lub inna poważna usterka. .NET Framework umożliwia tę elastyczność w powiązaniu wersji za pomocą zasad wersji.

Numery wersji zestawu

Każdy zestaw ma czteroczęściowy numer wersji w ramach jego tożsamości (czyli wersja 1.0.0.0.0 niektórych zestawów i wersja 2.1.0.2 są zupełnie różnymi tożsamościami w odniesieniu do modułu ładującego klasy). Uwzględnienie wersji w ramach tożsamości jest niezbędne do odróżnienia różnych wersji zestawu na potrzeby równoległego.

Części numeru wersji są główne, pomocnicze, kompilacje i poprawki. Nie zastosowano semantyki do części numeru wersji. Oznacza to, że clR nie wywnioskuje zgodności ani żadnych innych cech zestawu na podstawie sposobu przypisywanego numeru wersji. Jako deweloper możesz zmienić dowolną część tej liczby zgodnie z potrzebami. Mimo że nie ma semantyki stosowanej do formatu numeru wersji, poszczególne organizacje prawdopodobnie będą przydatne do ustanowienia konwencji dotyczących sposobu zmiany numeru wersji. Pomaga to zachować spójność w całej organizacji i ułatwia określenie elementów takich jak tworzenie określonego zestawu. Jedną z typowych konwencji jest następująca:

Główne lub drobne. Zmiany głównej lub pomocniczej części numeru wersji wskazują niezgodną zmianę. W ramach tej konwencji wersja 2.0.0.0 byłaby uznawana za niezgodną z wersją 1.0.0.0. Przykłady niezgodnej zmiany byłyby zmianą typów niektórych parametrów metody lub całkowitego usunięcia typu lub metody.

Twórz. Numer kompilacji jest zwykle używany do rozróżniania codziennych kompilacji lub mniejszych zgodnych wydań.

Wersja Zmiany numeru poprawki są zwykle zarezerwowane dla kompilacji przyrostowej wymaganej do naprawienia konkretnej usterki. Czasami usłyszysz ten numer nazywany "poprawką usterki awaryjnej" w tym, że poprawka jest często zmieniana po wysłaniu poprawki do określonego błędu do klienta.

Domyślne zasady wersji

Podczas rozpoznawania odwołań do zestawów udostępnionych clR określa, która wersja zależności ma być ładowana, gdy występuje odwołanie do tego zestawu w kodzie. Domyślne zasady wersji na platformie .NET są niezwykle proste. Podczas rozpoznawania odwołania clR pobiera wersję z manifestu wywołującego zestawu i ładuje wersję zależności z dokładnie tym samym numerem wersji. W ten sposób obiekt wywołujący otrzymuje dokładną wersję, którą został zbudowany i przetestowany. Te domyślne zasady mają właściwość, od której chroni aplikacje przed scenariuszem, w którym inna aplikacja instaluje nową wersję zestawu udostępnionego, od którego zależy istniejąca aplikacja. Pamiętaj, że przed platformą .NET istniejące aplikacje będą domyślnie używać nowego udostępnionego składnika. Jednak na platformie .NET instalacja nowej wersji zestawu udostępnionego nie ma wpływu na istniejące aplikacje.

Niestandardowe zasady wersji

Może wystąpić czas powiązania z dokładną wersją, z którą aplikacja została dostarczona, nie jest odpowiednia. Na przykład administrator może wdrożyć poprawkę o krytycznym błędzie w zestawie udostępnionym i chcieć, aby wszystkie aplikacje korzystały z tej nowej wersji niezależnie od wersji, z którą zostały utworzone. Ponadto dostawca zestawu udostępnionego mógł wysłać wydanie usługi do istniejącego zestawu i chce, aby wszystkie aplikacje zaczęły korzystać z wersji usługi zamiast oryginalnej wersji. Te scenariusze i inne są obsługiwane w .NET Framework za pośrednictwem zasad wersji.

Zasady wersji są określone w plikach XML i są po prostu żądaniem załadowania jednej wersji zestawu zamiast innej. Na przykład następujące zasady wersji kierują clR do załadowania wersji 5.0.0.1 zamiast wersji 5.0.0.0 zestawu o nazwie MarineCtrl:

 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependentAssembly
   <assemblyIdentity name="MarineCtrl" publicKeyToken="9335a2124541cfb9" />
      <bindingRedirect oldVersion="5.0.0.0" newVersion="5.0.0.1" />   
  </dependentAssembly>
</assemblyBinding>

Oprócz przekierowania z określonego numeru wersji do innej, można również przekierować z zakresu wersji do innej wersji. Na przykład następujące zasady przekierowuje wszystkie wersje z wersji 0.0.0.0 do 5.0.0.0 z MarineCtrl do wersji 5.0.0.1:

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependentAssembly
   <assemblyIdentity name="MarineCtrl" publicKeyToken="9335a2124541cfb9" />
      <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.1" />   
  </dependentAssembly>
</assemblyBinding>

Poziomy zasad wersji

Istnieją trzy poziomy, na których można zastosować zasady wersji na platformie .NET: zasady specyficzne dla aplikacji, zasady wydawcy i zasady dla całego komputera.

Zasady specyficzne dla aplikacji. Każda aplikacja ma opcjonalny plik konfiguracji, który może określić chęć powiązania aplikacji z inną wersją zestawu zależnego. Nazwa pliku konfiguracji różni się w zależności od typu aplikacji. W przypadku plików wykonywalnych nazwa pliku konfiguracji to nazwa pliku wykonywalnego i rozszerzenie ".config". Na przykład plik konfiguracji "myapp.exe" będzie "myapp.exe.config". Pliki konfiguracji aplikacji ASP.NET są zawsze "web.config".

Zasady wydawcy. Podczas gdy zasady specyficzne dla aplikacji są ustawiane przez dewelopera aplikacji lub administratora, zasady wydawcy są ustawiane przez dostawcę zestawu udostępnionego. Zasady wydawcy to oświadczenie o zgodności dostawcy dotyczące różnych wersji jej zestawu. Załóżmy na przykład, że dostawca udostępnionej kontrolki Windows Forms dostarcza wydanie usługi zawierające szereg poprawek usterek do kontrolki. Oryginalna kontrolka była w wersji 2.0.0.0, a wersja wydania usługi to 2.0.0.1. Ponieważ nowa wersja zawiera tylko poprawki błędów (bez zmian interfejsu API powodujące niezgodność) dostawca kontroli prawdopodobnie wyda zasady wydawcy z nową wersją, która powoduje, że istniejące aplikacje, które używały wersji 2.0.0.0.0, aby teraz rozpocząć korzystanie z wersji 2.0.0.1. Zasady wydawcy są wyrażane w formacie XML tak samo jak zasady aplikacji i całej maszyny, ale w przeciwieństwie do tych innych poziomów zasad zasady wydawcy są dystrybuowane jako sam zestaw. Głównym powodem tego jest zapewnienie, że organizacja zwalniającą zasady dla określonego zestawu jest tą samą organizacją, która wydała sam zestaw. Jest to realizowane przez wymaganie, aby zarówno oryginalny zestaw, jak i zestaw zasad otrzymał silną nazwę z tą samą parą kluczy.

Zasady dotyczące całej maszyny. Ostateczny poziom zasad to zasady dla całej maszyny (czasami nazywane zasadami administratora). Zasady dotyczące całego komputera są przechowywane w machine.config, które znajdują się w podkatalogu "config" w katalogu instalacji .NET Framework. Katalog instalacyjny to %windir%\microsoft.net\framework\%runtimeversion%. Instrukcje zasad wykonane w machine.config wpływają na wszystkie aplikacje uruchomione na maszynie. Zasady dotyczące całego komputera są używane przez administratorów w celu wymuszenia użycia określonej wersji zestawu przez wszystkich aplikacji na danym komputerze. Najbardziej komentowany scenariusz, w którym jest używany, jest to, że w globalnej pamięci podręcznej zestawów wdrożono poprawkę zabezpieczeń lub inną krytyczną poprawkę usterek. Po wdrożeniu zestawu stałego administrator będzie używał zasad wersji dla całego komputera, aby upewnić się, że aplikacje nie używają starej, uszkodzonej wersji zestawu.

Ocena zasad

Pierwszą rzeczą, jaką clR wykonuje, gdy powiązanie z silnie nazwanym zestawem określa wersję zestawu do powiązania. Proces rozpoczyna się od odczytania numeru wersji żądanego zestawu, który został zarejestrowany w manifeście zestawu tworzącego odwołanie. Następnie zasady są oceniane w celu określenia, czy którykolwiek z poziomów zasad zawiera przekierowanie do innej wersji. Poziomy zasad są oceniane w kolejności rozpoczynającej się od zasad aplikacji, a następnie wydawcy i administratora.

Przekierowanie znalezione na dowolnym poziomie zastępuje dowolną instrukcję wykonaną na poprzednim poziomie. Załóżmy na przykład, że zestaw A odwołuje się do zestawu B. Odwołaniem do B w manifeście A jest wersja 1.0.0.0. Ponadto zasady wydawcy dostarczane z zestawem B przekierowuje odwołanie z wersji 1.0.0.0 do 2.0.0.0.0. Ponadto istnieją zasady wersji to plik konfiguracji obejmujący całą maszynę, który kieruje odwołanie do wersji 3.0.0.0. W takim przypadku instrukcja wykonana na poziomie komputera zastąpi instrukcję wykonaną na poziomie wydawcy.

Pomijanie zasad wydawcy

Ze względu na kolejność stosowania trzech typów zasad przekierowanie wersji wydawcy (zasady wydawcy) może zastąpić zarówno wersję zarejestrowaną w metadanych zestawu wywołującego, jak i wszystkich ustawionych zasadach specyficznych dla aplikacji. Jednak wymuszanie, aby aplikacja zawsze akceptowała zalecenie wydawcy dotyczące przechowywania wersji, może prowadzić do powrotu do biblioteki DLL Hell. W końcu biblioteka DLL Hell jest spowodowana przede wszystkim trudnością z utrzymaniem zgodności z poprzednimi wersjami w udostępnionych składnikach. Aby uniknąć scenariusza, w którym aplikacja jest uszkodzona przez instalację nowej wersji składnika udostępnionego, system zasad wersji na platformie .NET umożliwia poszczególnym aplikacjom obejście zasad wydawcy. Innymi słowy, aplikacja może odrzucić zalecenie wydawcy dotyczące używanej wersji. Aplikacja może pominąć zasady wydawcy przy użyciu elementu "publisherPolicy" w pliku konfiguracji aplikacji:

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

<publisherPolicy apply="no"/>

</assemblyBinding>

Ustawianie zasad wersji za pomocą narzędzia do konfiguracji platformy .NET

Na szczęście .NET Framework są dostarczane z graficznym narzędziem administracyjnym, aby nie trzeba było martwić się o ręczne edytowanie plików zasad XML. Narzędzie obsługuje zarówno zasady wersji aplikacji, jak i całej maszyny. Narzędzie znajdziesz w sekcji Narzędzia administracyjne Panel sterowania. Początkowy ekran narzędzia administracyjnego wygląda jak Rysunek 6:

Rysunek 6. Narzędzie Administracja

W poniższych krokach opisano sposób ustawiania zasad specyficznych dla aplikacji:

  1. Dodaj aplikację do węzła Aplikacje w widoku drzewa. Kliknij prawym przyciskiem myszy węzeł Aplikacje i kliknij przycisk Dodaj. W oknie dialogowym Dodawanie zostanie wyświetlona lista aplikacji .NET do wyboru. Jeśli aplikacja nie znajduje się na liście, możesz ją dodać, klikając pozycję Inne.

  2. Wybierz zestaw, dla którego chcesz ustawić zasady. Kliknij prawym przyciskiem myszy węzeł Skonfigurowane zestawy i kliknij przycisk Dodaj. Jedną z opcji jest wybranie zestawu z listy zestawów, do których odwołuje się aplikacja, i wyświetlenie następującego okna dialogowego, jak pokazano na rysunku 7. Wybierz zestaw i kliknij pozycję Wybierz.

    Rysunek 7. Wybieranie zestawu

  3. W oknie dialogowym Właściwości wprowadź informacje o zasadach wersji. Kliknij kartę Zasady powiązania i wprowadź żądane numery wersji w tabeli, jak pokazano na rysunku 8.

    Rysunek 8. Karta Wiązanie zasad

Wdrożenie

Wdrożenie obejmuje co najmniej dwa różne aspekty: pakowanie kodu i dystrybucję pakietów do różnych klientów i serwerów, na których będzie uruchamiana aplikacja. Głównym celem .NET Framework jest uproszczenie wdrożenia (zwłaszcza aspekt dystrybucji), dzięki czemu można zainstalować instalację bez wpływu i wdrożenie xcopy. Samoopisujący charakter zestawów pozwala nam usunąć naszą zależność od rejestru, co znacznie upraszcza instalację, odinstalowywanie i replikację. Istnieją jednak scenariusze, w których xcopy nie jest wystarczające lub odpowiednie jako mechanizm dystrybucji. W takich przypadkach .NET Framework zapewnia rozbudowane usługi pobierania kodu i integrację z Instalatorem Windows.

Packaging

W pierwszej wersji .NET Framework dostępne są trzy opcje pakowania:

  • Zgodnie z kompilacją (biblioteki DLL i EXE). W wielu scenariuszach nie jest wymagane żadne specjalne opakowanie. Aplikację można wdrożyć w formacie utworzonym przez narzędzie programistyczne. Oznacza to, że kolekcja bibliotek DLL i EXE.
  • Pliki cab. Pliki cab mogą służyć do kompresji aplikacji w celu bardziej wydajnego pobierania.
  • Pakiety Instalatora Windows. Program Microsoft Visual Studio .NET i inne narzędzia instalacyjne umożliwiają tworzenie pakietów Instalatora Windows (pliki .msi). Instalator Windows umożliwia korzystanie z funkcji naprawy aplikacji, instalacji na żądanie i innych funkcji zarządzania aplikacjami systemu Microsoft Windows.

Scenariusze dystrybucji

Aplikacje .NET można rozpowszechniać na różne sposoby, w tym xcopy, pobieranie kodu i za pośrednictwem Instalatora Windows.

W przypadku wielu aplikacji, w tym aplikacji internetowych i usług sieci Web, wdrożenie jest tak proste, jak kopiowanie zestawu plików na dysk i uruchamianie ich. Odinstalowywanie i replikacja są równie proste — wystarczy usunąć pliki lub skopiować je.

.NET Framework zapewnia rozbudowaną obsługę pobierania kodu przy użyciu przeglądarki internetowej. W tym obszarze wprowadzono kilka ulepszeń, w tym:

  • Zerowy wpływ. Na maszynie nie są tworzone żadne wpisy rejestru.
  • Pobieranie przyrostowe. Elementy zestawu są pobierane tylko wtedy, gdy są przywoływane.
  • Pobierz izolowane do aplikacji. Kod pobrany w imieniu jednej aplikacji nie może wpływać na inne osoby na maszynie. Głównym celem obsługi pobierania kodu jest zapobieganie scenariuszowi, w którym użytkownik pobiera nową wersję niektórych składników udostępnionych jako efekt uboczny przeglądania określonej witryny sieci Web i niekorzystnie wpływa na inne aplikacje.
  • Brak okien dialogowych Authenticode. System zabezpieczeń dostępu do kodu służy do zezwalania na uruchamianie kodu mobilnego z częściowym poziomem zaufania. Użytkownicy nigdy nie będą prezentowani z oknami dialogowymi z prośbą o podjęcie decyzji o tym, czy ufają kodowi.

Na koniec platforma .NET jest w pełni zintegrowana z Instalatorem Windows i funkcjami zarządzania aplikacjami systemu Windows.

Podsumowanie

.NET Framework umożliwia instalację i adresy DLL Hell bez wpływu. Zestawy to samodzielnie opisujące jednostki wdrażania z możliwością obsługi wersji używane do włączania tych funkcji.

Możliwość tworzenia izolowanych aplikacji ma kluczowe znaczenie, ponieważ umożliwia tworzenie aplikacji, które nie będą miały wpływu na zmiany wprowadzone w systemie przez inne aplikacje. .NET Framework zachęca do tego typu aplikacji za pomocą zestawów prywatnych aplikacji wdrożonych w strukturze katalogów aplikacji.

Obok siebie jest podstawową częścią scenariusza udostępniania i przechowywania wersji na platformie .NET. Obok siebie umożliwia jednoczesne instalowanie i uruchamianie wielu wersji zestawu oraz umożliwia każdej aplikacji żądanie określonej wersji tego zestawu.

ClR rejestruje informacje o wersji między elementami aplikacji i używa tych informacji w czasie wykonywania, aby upewnić się, że załadowana jest właściwa wersja zależności. Zasady wersji mogą być używane zarówno przez deweloperów aplikacji, jak i administratorów w celu zapewnienia elastyczności w wyborze wersji danego zestawu.

Istnieje kilka opcji pakowania i dystrybucji dostępnych przez .NET Framework, w tym Instalatora Windows, pobierania kodu i prostego narzędzia xcopy.