# Matrix42 26.1 Legacy Extension Migration
Diese Notizen dokumentieren die bisherigen Learnings aus der Migration einer alten Matrix42 Extension inklusive Custom Web Service auf eine Matrix42 26.1 Sandboxed Extension.
Die Anleitung ist bewusst als wiederverwendbare Checkliste fuer weitere Legacy-Pakete formuliert. Sie trennt zwischen belastbaren Ergebnissen, verworfenen Zwischenansaetzen und Punkten, die bei jeder Extension erneut geprueft werden muessen.
## Zielbild
- Extension als .NET 8 Library mit `Matrix42.WebApi.Contracts`.
- Webservice-Controller von `Matrix42.WebApi.Contracts.ApiController` ableiten.
- Controller ueber `Matrix42.Hosting.Contracts.IDependencyResolver` konstruieren.
- Matrix42-Fachservices nur dort lazy aufloesen, wo sie wirklich gebraucht werden.
- Host-Konfig mit minimalen Modulen starten und gezielt erweitern.
- Paketbau in MSBuild/Visual Studio integrieren.
- Paketversion aus `AssemblyVersion` ableiten.
- Signing nur fuer eine eigene signed Build-Konfiguration aktivieren.
- Postman-Collection als Regressionstest fuer alte Client-URLs pflegen.
## Ausgangspunkt
Bei einer Portierung eines alten Produktstands muss der Zielstand klar sein. Fuer diesen Branch war der relevante alte Stand `26eac54f94`, nicht der spaetere neue Codezweig.
Wichtiges Learning: Bei einem 26.1-Kompatibilitaetsport keine neuen fachlichen Methoden, Obsolete-Markierungen oder Verhaltensaenderungen aus einem anderen Codezweig uebernehmen. Erst die alte Funktionalitaet lauffaehig machen, dann separate fachliche Aenderungen behandeln.
## Basisprojekt
Bewaehrte Projekt-Eigenschaften:
```xml
net8.0Librarywin-x64;linux-x64truedisabledisablefalsefalse......true
```
Referenzen auf Matrix42-DLLs sollen gegen die 26.1 Libraries zeigen und normalerweise `Private=false` haben, damit keine unnoetigen Matrix42-Plattform-DLLs ins Paket kopiert werden.
Die Host-Konfig muss exakt zum Assembly-Namen passen:
```text
.dll.host.config
```
## Paketbau
Das Paket wird ueber `M42SandboxedExtension.targets` gebaut.
Aktuelle Regeln in diesem Repo:
- `Debug` baut Debug-DLLs und ein Debug-Paket.
- `Release` baut ein unsigniertes Release-Paket.
- `Release_signed` baut ein Release-Paket und aktiviert `M42SignAssemblies=true`.
- Artefakte liegen getrennt nach Konfiguration unter `artifacts//`.
- Die Package-Version wird aus der `AssemblyVersion` der gebauten WebApi-Assembly gelesen.
- `M42PackageVersion` wurde entfernt und soll nicht wieder eingefuehrt werden.
Die zentrale Version liegt in `SharedAssemblyInfo.cs`.
Beispiele:
```powershell
dotnet build "C:\Workspace\C4IT FASD\F4SD_M42WebApi\C4IT - F4SD - M42WebApi.sln" -c Debug
dotnet build "C:\Workspace\C4IT FASD\F4SD_M42WebApi\C4IT - F4SD - M42WebApi.sln" -c Release
dotnet build "C:\Workspace\C4IT FASD\F4SD_M42WebApi\C4IT - F4SD - M42WebApi.sln" -c Release_signed
```
Visual Studio:
- `Debug`: Debugging und Testpakete.
- `Release`: Release ohne Signierung.
- `Release_signed`: Release mit Signierung.
Bei `Release_signed` werden alle Paket-DLLs in einem einzigen `signtool sign`-Aufruf signiert.
Das vermeidet eine separate Passwortabfrage pro DLL, wenn das Zertifikat interaktiv entsperrt werden muss.
Signierbare MSBuild-Properties:
```powershell
/p:M42SignAssemblies=true
/p:M42SignTool="C:\Path\To\signtool.exe"
/p:M42SignCertificateThumbprint=""
/p:M42SignCertificateFile="C:\Path\To\certificate.pfx"
/p:M42SignCertificatePassword=""
/p:M42SignTimestampUrl="http://rfc3161timestamp.globalsign.com/advanced"
/p:M42SignOptions="/a"
```
## Package-Struktur
Das neue Paket basiert auf einem `PackageTemplate` mit:
- `package.json`
- `install.xml`
- `install/...`
- `BasePackage/Assemblies` als Build-Ziel fuer Assemblies
Beim Portieren eines Legacy-Pakets:
1. Altes Paket entpacken.
2. WebAPI-Service (`PLSLServiceTypeWebAPI`) und Operationen (`PLSLWebServiceOperation`) identifizieren.
3. Extension-/Assembly-ID beibehalten, wenn ein Update statt einer Neuinstallation gewollt ist.
4. Operation-IDs nur dann aendern, wenn bewusst neue Operationen entstehen sollen.
5. Obsolete oder entfernte Schema-Attribute aus 26.1 entfernen.
6. Nach der ersten lauffaehigen Version die Webservice-Operationen in Matrix42 synchronisieren, exportieren und die synchronisierten Contracts in die Paketdateien mergen.
Wichtiges finales Learning zu Webservice-Operationen:
- Wenn ein Endpoint nur nach "Service synchronisieren" korrekt funktioniert, sind die `PLSLWebServiceOperation`-Contracts im Paket nicht mehr synchron zum Controller.
- Die synchronisierten Operationen exportieren und mit den bestehenden Paketdateien mergen.
- Bestehende `PLSLWebServiceOperation.ID`s nicht durch Export-IDs ersetzen, sonst entstehen auf Bestandssystemen doppelte Operationen.
- Bestehende `PDRAudienceClass.ID`s ebenfalls erhalten.
- Nur fachliche Operation-Felder uebernehmen: `ResponseContract`, `RequestContract`, `Name`, `RouteTemplate`, `SupportedOperation`, `Type`, `IsPublic`.
- Neue Operationen, die bisher nicht im Paket vorhanden waren, duerfen die exportierten IDs verwenden, wenn sie aus dem Zielsystem stammen, auf dem sie bereits synchronisiert wurden.
- Operation-Dateien nach Operation benennen, z. B. `getticketlist.dat`, `getpickup.dat`, `isalive.dat`. Das erleichtert Reviews und verhindert Verwechslungen mit generischen `02-01-xxxx PLSLWebServiceOperationType.dat`-Dateien.
- Jede Datei aus `PackageTemplate/install/0002_WebServiceOperation` muss in `PackageTemplate/install.xml` referenziert sein.
Validierung:
```powershell
# XML parsebar?
python -c "import pathlib,xml.etree.ElementTree as ET; [ET.parse(p) for p in pathlib.Path('PackageTemplate/install/0002_WebServiceOperation').glob('*.dat')]"
# Debug-Paket bauen und pruefen, ob alle Operation-Dateien im Paket liegen
dotnet build "C:\Workspace\C4IT FASD\F4SD_M42WebApi\C4IT - F4SD - M42WebApi.sln" -c Debug
```
Konkretes 26.1-Learning:
- `UsedInTypeSPSActivityTypeAlert` gibt es in 26.1 nicht mehr und muss aus dem Paket entfernt werden.
## Host-Konfig und Module
Mit so wenig Modulen wie moeglich starten. Jedes zusaetzliche Modul kann transitive Unity-Registrierungen erzwingen, die bereits beim Controller- oder Service-Aufbau scheitern.
Minimaler Startpunkt fuer einfache Endpoints:
```xml
```
Der aktuelle Stand dieser Extension benoetigt fuer alle Funktionen mehr Module, insbesondere wegen Journal, Storage, Pandora, Teams Notification, ServiceConnection, Auth und Aurora Search. Aktuelle Host-Konfig:
```xml
```
Regel: Wenn ein weiteres Interface nicht aufgeloest werden kann, nicht raten. In den Matrix42-DLLs nach dem Registrator/der Implementierung fuer genau dieses Interface suchen und nur das passende Modul laden.
## Controller-Konstruktion
Nicht so:
```csharp
public MyController(IEntityDataService entityDataService, IJournalService journalService, IPandoraUserProfile userProfile)
```
Das zwingt Unity, alle Services schon beim Erzeugen des Controllers aufzuloesen. Dadurch kann bereits `isAlive` scheitern, obwohl der Endpoint selbst keinen dieser Services braucht.
Bewaehrt:
```csharp
private readonly IDependencyResolver _resolver;
public MyController(IDependencyResolver resolver, IEnumerationProvider enumerationProvider)
{
_resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
_enumerationProvider = enumerationProvider ?? throw new ArgumentNullException(nameof(enumerationProvider));
}
private T GetRequiredService() where T : class
{
var service = _resolver.TryGet();
if (service != null)
return service;
throw new InvalidOperationException($"Required Matrix42 service is not registered: {typeof(T).FullName}");
}
```
Fachservices im jeweiligen Endpoint oder Helper lazy aufloesen.
## Dependency-Registrator
Die Extension kann eigene Sandbox-Registrierungen bereitstellen, wenn der Matrix42-Sandbox-Host eine Plattform-Instanz nicht selbst registriert.
Konkretes Learning:
- Fuer den Journal-Pfad fehlte `System.Web.Http.Description.IApiExplorer`.
- Die Extension registriert eine konkrete `ApiExplorer`-Instanz ueber `IDependencyRegistrator`.
- Das eigene Assembly muss dafuer als Host-Modul geladen werden.
Das ist kein Workaround im fachlichen Code, sondern eine Host-Registrierung fuer eine fehlende Infrastruktur-Dependency.
## WebAPI-Rueckgaben
Matrix42 serialisiert `HttpResponseMessage` in dieser Runtime nicht wie klassische ASP.NET Web API, sondern als Nutzdatenobjekt.
Nicht fuer normale Datenendpoints verwenden:
```csharp
Task
HttpResponseExtensions.CreateResponse(...)
```
Symptom:
```json
{"Version":"1.1","Content":{...},"StatusCode":200}
```
Bewaehrt:
- Datenendpoints geben direkte Nutzdaten zurueck, z. B. `Task>`, `Task