Instalacja ClickOnce

Instalacja aplikacji zawsze kojarzy się z kosztownymi pakietami do tworzenia instalatorów oraz długotrwałym testowaniem kompatybilności z wieloma układami aplikacji innych firm. W .NET 1.1 instalacja była już trochę prostsza, a w .NET 2.0 wprowadzono mechanizm ClickOnce.

Instalacja aplikacji zawsze kojarzy się z kosztownymi pakietami do tworzenia instalatorów oraz długotrwałym testowaniem kompatybilności z wieloma układami aplikacji innych firm. W .NET 1.1 instalacja była już trochę prostsza, a w .NET 2.0 wprowadzono mechanizm ClickOnce.

ClickOnce sprawia, że praktycznie nie ma różnicy w koszcie wdrożenia aplikacji WWW i aplikacji opartej na Windows Forms, a co ciekawsze, można łączyć oba te typy w jednym rozwiązaniu.

Aplikacje oparte na WWW stały się tak popularne m.in. z powodu bardzo niskiego kosztu utrzymania w porównaniu z tradycyjnymi. W firmie wdrożenie systemu wspomagającego działalność handlową opartą na WWW sprowadza się w zasadzie do utrzymania serwera. Jednak takie aplikacje, mimo rozbudowanych możliwości dynamicznych stron WWW, są zwykle mniej wygodne dla użytkownika, który woli okna, przeciąganie danych, wklejanie do Excela itp., bo wtedy szybciej pracuje.

W wypadku tradycyjnych aplikacji trzeba coś zainstalować na każdej stacji roboczej. Do tego dochodzą problemy z kontrolą wersji i generalnie utrzymaniem - co zrobić, gdy muszą działać równolegle dwie wersje systemu itp.

.NET 1.1 przyniósł tu dużą zmianę. Ponieważ pakiet jest strukturą samoopisującą się, wystarczy wgrać do jednego folderu wszystkie potrzebne pliki i w czasie działania zostaną one znalezione, a program będzie działał prawidłowo.

Standardowo .NET Framework do identyfikacji używa nazwy pakietu oraz jego wersji. We właściwościach projektu (generującego plik EXE lub DLL) na karcie Application po naciśnięciu przycisku Assembly Information można skonfigurować opis danego pakietu. Na samej karcie można podać Assembly Name , która jest taka sama, jak nazwa pliku z danym kodem MSIL. Uwaga! Opcja Root Namespace określa główną przestrzeń nazw dla danego pakietu (assembly). Jeżeli na przykład główna przestrzeń zostanie nazwana OneClickAppVBNS, to wszystkie przestrzenie definiowane poleceniem namespace zostaną "doklejone" niżej w hierarchii. Warto, aby nazwa pakietu odpowiadała nazwie głównej przestrzeni nazw (nawet jeżeli brzmiałaby MyApp.Util.Phone.dll).

Gdy dodajemy referencje do pakietu, kompilator posługuje się nazwą i numerem jego wersji aby wskazać, gdzie się znajduje dana funkcja. Podczas uruchamiania aplikacji najpierw sprawdza się, jaka jest prawidłowa wersja pakietu (assembly). W pliku konfiguracyjnym nazwaaplikacji.exe.config, generowanym na podstawie elementu app.config aplikacji, można zadeklarować "podstawienie" wersji - np. poinformować (jak w poniższym przykładzie), że ma być użyty pakiet LIB w wersji 3.4, mimo że aplikacja została skompilowana przy użyciu pakietu 3.2.

Nazwa pakietu jest dostępna na karcie aplication, ale już np. jego wersję ustawia się w oknie Assembly Information.

Nazwa pakietu jest dostępna na karcie aplication, ale już np. jego wersję ustawia się w oknie Assembly Information.

<runtime>

<gcConcurrent enabled="true" />

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

<publisherPolicy apply="yes" />

<dependentAssembly>

<assemblyIdentity name="LIB" publicKeyToken="79812b8147b5eae4" />

<bindingRedirect oldVersion="3.2" newVersion="3.4" />

</dependentAssembly>

</assemblyBinding>

</runtime>

Uwaga! Nie są w ogóle sprawdzane wersje, jeżeli aplikacja nie ma mocnej nazwy (czyli nie jest podpisana kluczem)! Warto podpisywać każdy pakiet, a już na pewno należy to zrobić, gdy udostępniamy aplikacje innym.

Podczas uruchamiania aplikacji sprawdza się, czy w danej AppDomain określony pakiet był już wczytany. Jeżeli tak, żądanie jest przekierowane do niego. Taki sposób ma jedną konsekwencję - konstruktor statyczny w klasie zawartej w danym pakiecie zostanie uruchomiony dopiero wtedy, gdy pakiet będzie wczytywany (a nie np. grupowo podczas startu aplikacji!).

Następnie sprawdzana jest zawartość GAC (Global Assembly Cache) - jeżeli znajduje się tam pakiet o prawidłowej nazwie/wersji/podpisie, to jest wczytywany. Jeżeli nie, rozpoczyna się jego poszukiwanie. Najpierw sprawdzana jest konfiguracja aplikacji oraz encje dependentAssembly i codeBase, które określają, gdzie szukać danej wersji pakietu. Jeżeli takich elementów nie ma albo nie dało się znaleźć pliku, przeszukiwane są foldery i podfoldery aplikacji. Miejsce poszukiwania (podfoldery) określa parametr probing. Uwaga - lokalizacją, od której rozpoczyna się przeszukiwanie, jest albo folder na dysku, albo dowolny URL (gdy aplikacja jest uruchomiona np. z http:/&#47server/myapp.exe - nadal jest to aplikacja do Windows, tyle że uruchamiana za pośrednictwem transportu HTTP - to plik może być w http:/&#47server/bin/lib.dll). Jeżeli potrzebny jest plik w określonym języku, to przeszukiwane są podfoldery o takich nazwach, jak lokalizacja (np. en-US, pl-PL). Dopiero potem wczytywany jest plik oznaczony jako "neutral", czyli niezależny od języka (lokalizacji). To interesujące, bo .NET może w zależności od ustawionego CultureInfo w danej AppDomain wczytać nie tylko zasoby w danym języku, ale wręcz kod z inną implementacją funkcji (np. dostosowaną do lokalnych wymagań metodą obliczania podatku itp).

Jeżeli wszystkie próby zawiodą, ostatnią instancją jest motor Windows Installer, który zostanie poproszony o zainstalowanie pliku DLL, który był np. zaznaczony jako "install on demand" (instaluj na życzenie). Dopiero gdy to się nie powiedzie, zostanie zgłoszony błąd. W poniższym przykładzie konfiguracji pakiet LIB jest wczytywany z serwera HTTP w wersji 3.4. Wszystkie dodatkowe biblioteki mogą być umieszczone w podfolderach bin, dll albo dll\private.

<configuration>

<runtime>

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

<dependentAssembly>

<assemblyIdentity name="LIB" publicKeyToken="79812b8147b5eae4" culture="neutral" />

<codeBase version="3.4" href="http:/&##47server/LIB.dll"/>

</dependentAssembly>

<probing privatePath="bin;dll;dll\private"/>

</assemblyBinding>

</runtime>

</configuration>

Fuslogvw.exe to narzędzie, które pozwala dokładnie prześledzić odszukiwanie potrzebnych pakietów. Domyślnie pokazuje tylko informacje o błędach, ale jeżeli klucz w rejestrze HKLM\Software\Microsoft\Fusion\ForceLog będzie miał wartość 1, to zobaczymy wszystkie wpisy i np. sprawdzimy, czy pakiet jest rzeczywiście wczytywany z lokalnego folderu, a nie z GAC.


Zobacz również