24 KiB
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 parallele Pflege der Legacy- und Sandbox-Varianten sowie der manuelle TFS-Rueckweg sind in docs/legacy-sandbox-development.md beschrieben.
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.ApiControllerableiten. - Controller ueber
Matrix42.Hosting.Contracts.IDependencyResolverkonstruieren. - 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
AssemblyVersionableiten. - 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:
<TargetFramework>net8.0</TargetFramework>
<OutputType>Library</OutputType>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<AppendRuntimeIdentifierToOutputPath>true</AppendRuntimeIdentifierToOutputPath>
<Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<M42ExtensionId>...</M42ExtensionId>
<M42AssemblyPattern>...</M42AssemblyPattern>
<M42BuildPackage>true</M42BuildPackage>
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:
<AssemblyName>.dll.host.config
Paketbau
Das Paket wird ueber M42SandboxedExtension.targets gebaut.
Aktuelle Regeln in diesem Repo:
Debugbaut Debug-DLLs und ein Debug-Paket.Releasebaut ein unsigniertes Release-Paket.Release_signedbaut ein Release-Paket und aktiviertM42SignAssemblies=true.- Artefakte liegen getrennt nach Konfiguration unter
artifacts/<Configuration>/. - Die Package-Version wird aus der
AssemblyVersionder gebauten WebApi-Assembly gelesen. M42PackageVersionwurde entfernt und soll nicht wieder eingefuehrt werden.
Die zentrale Version liegt in SharedAssemblyInfo.cs.
Beispiele:
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:
/p:M42SignAssemblies=true
/p:M42SignTool="C:\Path\To\signtool.exe"
/p:M42SignCertificateThumbprint="<thumbprint>"
/p:M42SignCertificateFile="C:\Path\To\certificate.pfx"
/p:M42SignCertificatePassword="<password>"
/p:M42SignTimestampUrl="http://rfc3161timestamp.globalsign.com/advanced"
/p:M42SignOptions="/a"
Package-Struktur
Das neue Paket basiert auf einem PackageTemplate mit:
package.jsoninstall.xmlinstall/...uninstall.xmluninstall/...uninstall_data.xmlBasePackage/Assembliesals Build-Ziel fuer Assemblies
Deinstallation
Eine Sandboxed Extension unterstuetzt die Matrix42-Paketdeinstallation nur, wenn das Paket eigene Uninstall-Skripte mitliefert. Fuer dieses Paket gilt:
uninstall.xmlentfernt den WebAPI-Service, alle eigenen Webservice-Operationen, Actions, Data Queries, die F4SD-Navigation, den F4SD-Quick-Call, die F4SD-Rolle und die eigene Lokalisierung.- Die vier globalen C4IT-Navigationseintraege werden nicht entfernt, weil sie von weiteren C4IT-Paketen gemeinsam verwendet werden koennen.
- Schema, Pickup-Werte, Konfigurationseintrag, Dataset-Views und Previews bleiben als Konfigurationsdaten bestehen. Deshalb ist
uninstall_data.xmlabsichtlich leer. - Der abschliessende Post-Schritt entfernt die
dat-Eintraege dieses Pakets ausSchemaScripts, damit eine spaetere Neuinstallation die Installationsskripte erneut ausfuehren kann. - Jede
.del-Datei verwendet nur eine aus dem Installationsobjekt oder einem Matrix42-Herstellerpaket verifizierte Kombination ausObjectIdundTypeId. Typ-IDs duerfen nicht geraten werden.
Beim Hinzufuegen eines paket-eigenen Objekts muss immer geprueft werden, ob auch uninstall.xml, eine passende .del-Datei und UnregisterInstallScripts_Sobu.post erweitert werden muessen.
Beim Portieren eines Legacy-Pakets:
- Altes Paket entpacken.
- WebAPI-Service (
PLSLServiceTypeWebAPI) und Operationen (PLSLWebServiceOperation) identifizieren. - Extension-/Assembly-ID beibehalten, wenn ein Update statt einer Neuinstallation gewollt ist.
- Operation-IDs nur dann aendern, wenn bewusst neue Operationen entstehen sollen.
- Obsolete oder entfernte Schema-Attribute aus 26.1 entfernen.
- 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.IDs nicht durch Export-IDs ersetzen, sonst entstehen auf Bestandssystemen doppelte Operationen. - Bestehende
PDRAudienceClass.IDs 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 generischen02-01-xxxx PLSLWebServiceOperationType.dat-Dateien. - Jede Datei aus
PackageTemplate/install/0002_WebServiceOperationmuss inPackageTemplate/install.xmlreferenziert sein.
Validierung:
# 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:
UsedInTypeSPSActivityTypeAlertgibt 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 version="1.0" encoding="utf-8" ?>
<host xmlns="urn:m42/host.config">
<modules>
<module assembly="Matrix42.DataLayer.Persistence" />
</modules>
<sections></sections>
</host>
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:
<modules>
<module assembly="C4ITF4SDM42WebApi" />
<module assembly="Matrix42.DataLayer.Persistence" />
<module assembly="Matrix42.Services.WebApi" />
<module assembly="Matrix42.ServiceRepository.BizLogic" />
<module assembly="Matrix42.Pandora.ServiceStore" />
<module assembly="Matrix42.Pandora.Persistence" />
<module assembly="Matrix42.Pandora.BizLogic" />
<module assembly="Matrix42.Pandora.Services" />
<module assembly="Matrix42.Distributed.Redis.Cache" />
<module assembly="Matrix42.StorageService.BizLogic" />
<module assembly="Matrix42.MsTeamsNotification.BizLogic" />
<module assembly="Matrix42.ServiceConnection.Persistence" />
<module assembly="Matrix42.Auth.BizLogic" />
<module assembly="Matrix42.ServiceConnection.BizLogic" />
<module assembly="Matrix42.Integration.Aurora.General" />
<module assembly="Matrix42.Integration.Aurora.Search.BizLogic" />
<module assembly="update4u.SPS.ComplianceRules.BizLogic" />
<module assembly="update4u.SPS.Security" />
<module assembly="Matrix42.BizLogic.Journal" />
<module assembly="Matrix42.ServiceManager.BizLogic" />
</modules>
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:
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:
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<T>() where T : class
{
var service = _resolver.TryGet<T>();
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 ueberIDependencyRegistrator. - 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:
Task<HttpResponseMessage>
HttpResponseExtensions.CreateResponse(...)
Symptom:
{"Version":"1.1","Content":{...},"StatusCode":200}
Bewaehrt:
- Datenendpoints geben direkte Nutzdaten zurueck, z. B.
Task<List<T>>,Task<object>oderTask<EntityEnumeration>. - Leere Listen duerfen nicht
nullsein. isAlivegibtIHttpActionResultmit einem expliziten HTTP-204-Response zurueck.
Healthcheck:
[Route("isAlive"), HttpGet]
public IHttpActionResult isAlive()
{
var response = new HttpResponseMessage(HttpStatusCode.NoContent)
{
RequestMessage = Request
};
response.Headers.ConnectionClose = true;
return ResponseMessage(response);
}
Nicht verwenden:
public void isAlive()
Symptom:
{"result":null,"parameters":{}}
Null-Rueckgaben
Matrix42/Pandora behandelt null als fehlerhafte Operation-Response.
Symptom:
Method getTicketList returned null
Regel:
- Listenendpoints geben bei "nichts gefunden"
new List<T>()zurueck. - Objekte geben ein leeres DTO oder 204 zurueck, aber nicht unbewusst
null. - Strings koennen bei Bedarf
string.Emptystattnullliefern.
Routen und Parameterbindung
Finales Learning: Fuer Legacy-Kompatibilitaet muessen Route, PLSLWebServiceOperation.RouteTemplate, [FromUri] und die alten Client-URLs zusammen betrachtet werden.
Bewaehrte Regeln:
- Die Route-Attribute aus der funktionierenden Legacy-Version uebernehmen.
- Query-basierte Legacy-Endpoints bleiben query-basiert, z. B.
[Route("getTicketList")]. - Path-basierte Legacy-Endpoints bleiben path-basiert, z. B.
[Route("getPickup/{name}")]. - GET-Parameter mit
[FromUri]markieren. - Zusaetzlich einen kleinen zentralen Query-Fallback verwenden, weil in 26.1 einzelne optionale Queryparameter trotz
[FromUri]nicht immer in der Methode ankamen. - Keine doppelten Controller-Methoden fuer alte und neue URL-Formen bauen.
- Die Postman-Collection testet bewusst die alten Client-URLs.
Beispiel Query-Route:
[Route("getDirectLinkCreateTicket"), HttpGet]
public async Task<DirectLink> getDirectLinkCreateTicket(
[FromUri] string sid = "",
[FromUri] string assetname = "")
{
sid = QueryValue(sid, nameof(sid));
assetname = QueryValue(assetname, nameof(assetname));
...
}
Beispiel Path-Route mit zusaetzlichen Queryparametern:
[Route("getPickup/{name}"), HttpGet]
public async Task<EntityEnumeration> getPickup(
[FromUri] string name,
[FromUri] EntityEnumerationVisibilityMode mode = EntityEnumerationVisibilityMode.None,
[FromUri] int group = -1)
{
name = QueryValue(name, nameof(name));
mode = QueryValue(mode, nameof(mode));
group = QueryValue(group, nameof(group));
...
}
Der zentrale Query-Fallback ist bewusst klein und verwendet die strukturierte WebAPI-API statt eigenes URL-Parsen:
private string GetQueryValue(string name)
{
return Request?.GetQueryNameValuePairs()
.FirstOrDefault(pair => string.Equals(pair.Key, name, StringComparison.OrdinalIgnoreCase))
.Value;
}
private string QueryValue(string value, string name)
{
return GetQueryValue(name) ?? value ?? string.Empty;
}
Betroffene alte Testformate:
getTicketList?sid=...&hours=...&queueoption=...&queues=...
getDirectLinkCreateTicket?sid=...&assetname=...
getDirectLinkF4SD?eoid=...&type=...
getPickup/<name>?mode=...&group=...
Pickups und Enumerations
IEntityDataService.GetEnumeration(...) ist bequem, zieht aber Pandora-Services herein. Das war fuer reine Pickups zu schwer.
Bewaehrt:
Matrix42.Persistence.Contracts.IEnumerationProvider
Dieser Service kommt ueber Matrix42.DataLayer.Persistence und liefert eine DataTable. Wenn der alte API-Vertrag EntityEnumeration bleiben soll, muss die DataTable selbst gemappt werden.
Gepruefte Alternativen:
Matrix42.Pandora.Contracts.IEntityDataService: liefert direktEntityEnumeration, benoetigt aber Pandora-Module.update4u.SPS.DataLayer.Contracts.IPickupDataService: liefert ebenfallsDataTable, ohne klaren Vorteil gegenueberIEnumerationProvider.
Empfehlung:
- Fuer reine Pickup-Lesefunktionen
IEnumerationProviderverwenden. - Pandora nur laden, wenn ein Endpoint es wirklich benoetigt.
Aktueller Benutzer
IPandoraUserProfile nicht im Controller injizieren.
Fuer getMyRoleMemberships reicht der Matrix42 Principal:
var principal = Thread.CurrentPrincipal as IM42Principal;
var userId = principal?.InteractivePrincipal?.M42Identity?.UserFragmentID
?? principal?.M42Identity?.UserFragmentID
?? Guid.Empty;
Danach kann der vorhandene ASQL-/Helper-Code mit der Guid weiterarbeiten.
Ticket-Historie und Journal
Ziel: den Matrix42-Service nutzen, nicht eigene Journal-Logik nachbauen.
Finaler Ansatz:
IJournalServiceueber den Matrix42-Resolver laden.- Keine direkte Konstruktion von
JournalService. - Keine eigenen DispatchProxy-/NoOp-Services.
- Keine HTTP-Weiterleitung an interne Admin-APIs.
- Keine Storage-Fallback-Journal-Implementierung als finaler Pfad.
GetJournalListper Reflection gegen die zur Laufzeit vorhandene Signatur aufrufen, weil sich die Signatur zwischen 26.1 Patch-Leveln unterscheiden kann.
Warum Reflection hier akzeptiert wurde:
- Der alte direkte Compile-Time-MethodRef brach mit
MissingMethodException. - Die geladene Runtime-DLL hatte eine andere
IJournalService.GetJournalList-Signatur. - Die Reflection sucht kompatible Journal-Reader-Methoden und liefert klare Diagnose, wenn keine passende Signatur existiert.
Typische Fehler auf dem Weg:
Method not found: IJournalService.GetJournalList(...)
IJournalService could not be resolved
IExternalAuthService is an interface and cannot be constructed
IOAuth2AuthorizeService is an interface and cannot be constructed
IApiExplorer is an interface and cannot be constructed
IRequestPropertiesProvider is an interface and cannot be constructed
IExternalSearchService is an interface and cannot be constructed
Learning: Bei diesen Fehlern nicht weiter im Endpoint herumprobieren, sondern die fehlende Host-Registrierung bzw. das passende Matrix42-Modul identifizieren.
Overview-Endpoints
getTicketOverviewCounts liefert Counts fuer mehrere Keys.
getTicketOverviewRelations nimmt genau einen key und ein count.
Postman-Learning:
getTicketOverviewCounts personalundgetTicketOverviewCounts roleleitenscope,overviewKeyundoverviewRelationExpectedCountab.getTicketOverviewRelationsnutzt diese Variablen.- Der Relations-Test erwartet, dass
response.lengthdem vorher abgeleiteten Count entspricht. - Im normalen Collection-Lauf ueberschreibt
roledie Werte vonpersonal, weilrolenachpersonalausgefuehrt wird.
Direct Link
Fuer F4SD Direct Links ist der Typ in der alten Integration nicht der Matrix42 ActivityType, sondern der F4SD-Typ.
Postman setzt deshalb nach getTicketList:
pm.collectionVariables.set("type", "ticket");
objectType bleibt separat auf ticket.ActivityType, falls der technische Matrix42-Typ fuer andere Tests gebraucht wird.
Postman-Collection
Die Collection ist Teil der Migration und Regression.
Regeln:
- Basic Auth ueber Variablen
basicUsernameundbasicPassword. baseUrlenthaelt/m42Services.- Legacy-Query-Routen testen, nicht nur neue path-basierte Formen.
getTicketListziehteoidundticketObjectIdausTicketObjectId.typefuer Direct Link bleibtticket.isAliveerwartet 204 und keinen Body.- Allgemeiner Test erkennt versehentlich serialisierte
HttpResponseMessage-Objekte.
Smoke-Test-Reihenfolge
Nach jeder Paketinstallation:
GET /m42Services/api/<prefix>/isaliveErwartung: HTTP 204 No Content.GET /m42Services/api/<prefix>/getpickup/<PickupName>Erwartung: JSON-Nutzdaten, keineHttpResponseMessage-Huelle.GET /m42Services/api/<prefix>/getMyRoleMembershipsErwartung: aktueller Benutzer und Rollen, keinIPandoraUserProfile-Fehler.GET /m42Services/api/<prefix>/getTicketList?...Erwartung: leere Liste oder Tickets, aber keinreturned null.- Direct Links mit Legacy-Query-Routen.
- Overview Counts und Relations.
- Journal-/History-Endpoints zuletzt, weil hier die meisten Matrix42-Services transitiv benoetigt werden.
Typische Fehlersymptome
Cannot create instance of <Controller>: The current type, <Interface>, is an interface and cannot be constructed.
Meist direkte Konstruktor-Injection oder fehlendes Host-Modul.
Could not load type 'System.Web.Routing.RouteTable'
Ungeeignetes altes System.Web-/WebApi-Modul in der Sandbox. Ursache entfernen, nicht weitere Alt-Abhaengigkeiten nachladen.
IApiExplorer is an interface and cannot be constructed
Sandbox-Host stellt diese WebApi-Explorer-Instanz nicht automatisch bereit. Ueber eigenen IDependencyRegistrator registrieren.
{"Version":"1.1","Content":{...},"StatusCode":200}
Ein HttpResponseMessage wurde als DTO serialisiert. Rueckgabe auf direkten Nutzdatentyp umstellen.
{"result":null,"parameters":{}}
Void-Endpoint oder falsch behandelte leere Rueckgabe. Fuer NoContent einen IHttpActionResult mit HTTP 204 liefern.
Method <name> returned null
Endpoint gibt null zurueck. Leeres DTO oder leere Liste zurueckgeben.
Verworfene Zwischenansaetze
Diese Ansaetze haben nicht nachhaltig geholfen und sollen nicht erneut aufgebaut werden:
- Matrix42-Fachinterfaces direkt im Controller-Konstruktor injizieren.
- Immer mehr Module auf Vorrat laden, ohne die konkrete fehlende Registrierung zu kennen.
HttpResponseMessageals Datenantwort verwenden.- Query-Parameter per eigenem Helper aus
RequestUrilesen. - Doppelte Controller-Methoden fuer alte Query-URLs und neue Path-URLs bauen.
JournalServicedirekt konstruieren.- NoOp-/Proxy-Abhaengigkeiten fuer Journal-Services erzeugen.
- Journal-Historie aus unvollstaendigen Kommentarfeldern nachbauen.
- Interne Matrix42 Admin-Webservices als finalen Journal-Pfad weiterleiten.
Migrationsablauf fuer weitere Extensions
- Ziel-Commit der Legacy-Funktionalitaet festlegen.
- Altes Paket entpacken und IDs dokumentieren.
- Herstellerbeispiel/Scaffolder-Struktur als 26.1-Referenz verwenden.
- Projekt auf .NET 8 und
Matrix42.WebApi.Contracts.ApiControllerumstellen. - Controller-Konstruktor auf minimale Infrastruktur-Services reduzieren.
- Host-Konfig minimal starten.
- Package-Build in MSBuild integrieren.
- AssemblyVersion als einzige Package-Versionsquelle verwenden.
- WebAPI-Rueckgaben auf direkte DTOs/Listen umstellen.
isAliveauf echten 204 umstellen.- Controller-Routen aus der funktionierenden Legacy-Version uebernehmen.
- GET-Parameter mit
[FromUri]versehen und fehlende Querywerte zentral ueberRequest.GetQueryNameValuePairs()nachziehen. - Pickups zuerst ueber schlanke Services loesen.
- Komplexe Matrix42-Services erst bei Bedarf laden.
- Bei Unity-Fehlern konkrete Implementierung/Registrator suchen.
- Webservice-Operationen nach erfolgreicher Installation in Matrix42 synchronisieren.
- Synchronisierte Operationen exportieren und in die Paketdateien mergen, ohne bestehende IDs zu ersetzen.
- Operation-Dateien sprechend nach Operation benennen und in
install.xmlreferenzieren. - Postman-Collection fuer alte Client-Routen aufbauen.
- Paket installieren, Service synchronisieren und Smoke-Tests ausfuehren.
- Erst nach erfolgreicher Kompatibilitaet fachliche Weiterentwicklungen einbringen.
Git- und Datei-Hinweise
- Vor Aenderungen
git statuspruefen. - Unrelated/untracked Dateien nicht mitcommitten.
- Textdateien in diesem Repo mit CRLF speichern.
.dat-Dateien behalten ihren UTF-8-BOM.- Controller-/JSON-Dateien ohne unnoetigen BOM lassen.
- Debug-Build fuer Debugging, Release/Release_signed fuer Auslieferung.
- Postman-Collection nach JSON-Aenderungen immer parsen/validieren.