# Matrix42 26.1 Extension/Webservice Migration
Diese Notizen dokumentieren die Learnings aus der Migration der alten F4SD Matrix42 Extension inklusive Custom Web Service auf die Matrix42 26.1 Sandboxed Extension Struktur.
Ausgangspunkt der eigentlichen 26.1-Migration war Commit `6c6ac272cd43` (`feat: support Matrix42 26.1 sandboxed web api`, 2026-06-26 11:44 +0200). Die Punkte hier sind bewusst als Checkliste fuer weitere Extensions formuliert.
## 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 nicht direkt im Controller-Konstruktor injizieren.
- Host-Konfig so klein wie moeglich halten.
- Paketbau in den Visual-Studio-/MSBuild-Prozess integrieren.
- Runtime zuerst mit minimalen Endpoints pruefen (`isAlive`, einfache Datenabfrage), dann erst komplexere Services aktivieren.
## Projektstruktur und Paketbau
Bewaehrte Projekt-Eigenschaften:
```xml
net8.0Librarywin-x64;linux-x64truefalse...C4ITF4SD*.*true
```
Das Package wird ueber `M42SandboxedExtension.targets` gebaut. Die Paketversion wird automatisch aus der `AssemblyVersion` der gebauten WebApi-Assembly gelesen. In diesem Repo wird diese zentral in `SharedAssemblyInfo.cs` gepflegt.
Ein erfolgreicher Release-Build erzeugt:
```text
artifacts// v/
artifacts// v.zip
```
Builds signieren die DLLs nicht automatisch. Signieren ist optional und muss explizit aktiviert werden. Wenn `M42SignAssemblies=true` gesetzt ist, werden die DLLs im Package vor dem Package-Build per Authenticode signiert.
Konfigurierbare 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"
```
Build-Befehl:
```powershell
dotnet build "C:\Workspace\C4IT FASD\F4SD_M42WebApi\C4IT - F4SD - M42WebApi.sln" -c Release
```
Signierter Release-Build:
```powershell
dotnet build "C:\Workspace\C4IT FASD\F4SD_M42WebApi\C4IT - F4SD - M42WebApi.sln" -c Release_signed
```
In Visual Studio kann oben in der Konfiguration `Release` fuer einen unsignierten Build oder `Release_signed` fuer einen signierten Build gewaehlt werden.
## Host-Konfig
Die Host-Konfig muss exakt zum Assembly-Namen passen:
```text
C4ITF4SDM42WebApi.dll.host.config
```
Final bewaehrte Minimal-Konfig:
```xml
```
Wichtig: Module nicht auf Vorrat laden. Jedes zusaetzliche Modul kann transitive Unity-Registrierungen erzwingen, die fuer den konkreten Webservice gar nicht benoetigt werden.
Module duerfen nicht auf Vorrat geladen werden. Fuer Endpunkte, die Matrix42-Services nutzen, muessen die transitiven Abhaengigkeiten aber vollstaendig als Host-Module registriert werden. Fuer den finalen `IJournalService`-Pfad wurden unter anderem folgende Module benoetigt:
- `Matrix42.Pandora.Persistence`
- `Matrix42.Pandora.ServiceStore`
- `Matrix42.Pandora.BizLogic`
- `Matrix42.Pandora.Services`
- `Matrix42.MsTeamsNotification.BizLogic`
- `Matrix42.Integration.Aurora.General`
- `Matrix42.Integration.Aurora.Search.BizLogic`
- `Matrix42.ServiceManager.BizLogic`
- eigenes Webservice-Assembly als Host-Modul
Waehrend der Migration zeigten fehlende Module oder fehlende Sandbox-Host-Registrierungen unter anderem folgende Fehler:
```text
IEntityDataService is an interface and cannot be constructed
IUserProfileRepository is an interface and cannot be constructed
IApiExplorer is an interface and cannot be constructed
IComplianceRuleManager is an interface and cannot be constructed
IRequestPropertiesProvider is an interface and cannot be constructed
IExternalSearchService is an interface and cannot be constructed
```
## Controller-Konstruktion
Nicht so:
```csharp
public MyController(IEntityDataService entityDataService, IJournalService journalService, IPandoraUserProfile userProfile)
```
Diese direkte Konstruktor-Injection zwingt Matrix42/Unity, alle Services schon beim Erzeugen des Controllers aufzuloesen. Dadurch kann bereits `isAlive` scheitern, obwohl der Endpoint selbst keinen dieser Services nutzt.
Besser:
```csharp
private readonly IDependencyResolver _resolver;
public MyController(IDependencyResolver resolver)
{
_resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
}
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 dann nur im jeweiligen Endpoint oder Helper lazy aufloesen.
## WebAPI-Rueckgaben
Matrix42 serialisiert manche Rueckgabetypen anders als klassische ASP.NET Web API.
Bewaehrt:
- Datenendpoints geben direkt Nutzdaten zurueck, z. B. `Task` oder `Task