← Blog
.NET FrameworkAzure DevOpsCOMCI/CD

Osiem agentów, jeden COM: jak naprawiliśmy build .NET w Azure DevOps

Opublikowano · 2 min czytania · Tomasz Dłuski

Pipeline miał zbudować projekt .NET Framework 4.8 z referencją COMReference. Przed kompilacją rejestrował DLL komponentu COM, a po zakończeniu ją wyrejestrowywał. Przy jednym jobie wszystko się zgadzało. Klient miał jednak osiem agentów Azure DevOps na jednej VM. Wystarczyły dwa równoległe joby, żeby doszło do wyścigu.

Osobne katalogi, wspólny rejestr

Agenty miały własne katalogi robocze, ale rejestracja komponentu była wspólna dla maszyny. COMReference rozwiązywał zależność przez rejestr Windows, więc stan przygotowany przez jeden job wpływał na drugi. W naszym skrypcie istniejąca rejestracja wystarczała, żeby drugi job przeszedł dalej. Na przykładzie dwóch z ośmiu agentów wyglądało to tak:

Jedna VM, wspólny rejestr

Przykład dwóch z ośmiu agentów

Najedź na element, aby zobaczyć szczegóły.

Przed: wspólna zależność

Agent A

checkout A

Build OK → cleanup

Wyrejestrowuje COM

Rejestr COM

jeden wpis dla całej VM

Wpis usunięty przez A

Agent B

checkout B

Build failed

Nie da się rozwiązać COMReference

A sprząta, zanim B dojdzie do kompilacji. B traci zależność i build się wywala.

Po: każdy job ma własny interop

Przygotowane wcześniej: typy COM → tlbimp.exe → assembly .NET

Agent A

checkout A

Własna kopia interopu

Cleanup usuwa tylko pliki A

Agent B

checkout B

Własna kopia interopu

Build succeeded

Schemat dotyczy kompilacji. Aplikacja nadal potrzebuje COM przy uruchomieniu.

Samo skasowanie DLL nie wyrejestrowuje COM: może zostawić wpis wskazujący nieistniejący plik. U nas problemem był cały cykl przygotowania i sprzątania współdzielonej zależności. To, że komponent istniał na początku joba B, nie gwarantowało jego dostępności podczas kompilacji.

Rozwiązanie: biblioteka interop

Wydzieliliśmy warstwę interop do osobnej biblioteki interop.comproject.csproj. Główny projekt dostał zwykłą zależność .NET do tej warstwy. Jego build przestał wymagać rejestrowania i wyrejestrowywania COM na współdzielonym agencie.

Wrapper wygenerowaliśmy za pomocą tlbimp.exe na podstawie biblioteki typów komponentu COM. Powstałe assembly .NET dostarcza typy interop potrzebne do kompilacji. Build aplikacji korzysta z gotowej biblioteki, zamiast rozwiązywać COMReference przez rejestr współdzielonej VM.

Dzięki temu cleanup jednego joba przestał podcinać kompilację drugiego. Zależność od samego komponentu COM podczas uruchamiania aplikacji pozostała osobną sprawą.

Dokumentacja Microsoft: gotowe biblioteki interop i tlbimp.exeWróć do bloga