Development 29. September 2026 6 min Lesezeit

N:M-Daten on demand holen mit Power Pages Server Logic

Die Web API stolpert beim N:M-Lesen. Server Logic liest serverseitig per $expand, on demand. Live verifiziert, samt der Sicherheitsfallstricke.

Im vorigen Beitrag habe ich eine Many-to-many-Beziehung mit Liquid FetchXML gelesen. Das funktioniert, aber die Daten werden beim Seitenaufbau geholt: vorgeladen, ob der Besucher sie je ansieht oder nicht.

Manchmal wollen Sie das Gegenteil, nämlich die verknüpften Datensätze on demand laden, erst wenn jemand eine Zeile aufklappt oder ein Detailpanel öffnet, ohne kompletten Reload und ohne die Abfrage im Browser offenzulegen. Genau dafür ist Server Logic da. Und sie beantwortet eine Frage, die der FetchXML-Beitrag offengelassen hat: Kann ein serverseitiger Aufruf N:M über $expand lesen, also über den bequemen Weg, an dem die Portal Web API stolpert? Ich habe es live getestet. Er kann.

Was Server Logic ist

Mit Server Logic führen Sie JavaScript serverseitig als Teil der Site-Laufzeit aus. Sie ist seit April 2026 allgemein verfügbar (Public Preview seit Oktober 2025). Code und Konfiguration liegen in Dataverse, wandern also mit Ihren Solutions und Pipelines wie jede andere Power-Pages-Komponente.

Zwei Eigenschaften sind hier entscheidend:

  • Sie läuft serverseitig, der Browser sieht weder die Abfrage noch die Verbindung. Sie schreiben natives JavaScript (ECMAScript 2023) ohne Browser-APIs: kein DOM, kein fetch, kein XMLHttpRequest.
  • Sie ist an Web Roles und Tabellenberechtigungen gebunden, genau wie der Rest des Portals. Sie ist keine erhöhte Hintertür. Dazu unten mehr, denn das ist der Teil, den viele falsch einschätzen.

Angelegt wird sie im Design Studio unter Einrichten, Server logic, den Code bearbeiten Sie dann in Visual Studio Code mit IntelliSense und Kompilierprüfung. Jede HTTP-Methode entspricht einer Funktion, die Sie definieren: get(), post(), put(), patch(), del().

N:M aus Server Logic lesen

Innerhalb von get() sprechen Sie Dataverse über das Objekt Server.Connector.Dataverse an. RetrieveMultipleRecords nimmt den Entity-Set-Namen und einen OData-Optionsstring:

function get() {
  try {
    var options =
      "$select=pwrprtl_installation_name" +
      "&$expand=pwrprtl_installation_product($select=pwrprtl_product_name)";
    return Server.Connector.Dataverse.RetrieveMultipleRecords(
      "pwrprtl_installations",
      options
    );
  } catch (err) {
    Server.Logger.Error("GET failed: " + err.message);
    return JSON.stringify({ status: "error", message: err.message });
  }
}

Die Microsoft-Doku zeigt für diese Methode nur $select und $top. Ob $expand über eine N:M-Navigation-Property funktioniert, ist nicht dokumentiert. Deshalb habe ich genau das im Demo-Portal aufgebaut (dieselben zwei benutzerdefinierten Tabellen Installation und Product mit N:M-Beziehung aus dem letzten Beitrag) und aufgerufen.

Das Ergebnis kommt sauber verschachtelt zurück:

Der Server-Logic-Endpunkt liefert HTTP 200 mit den per expand verschachtelten N:M-Produkten je Installation

Eine Installation, ihre zwei verknüpften Produkte (Pump A, Valve B), verschachtelt unter pwrprtl_installation_product, in einem einzigen Aufruf. Das ist genau der bequeme Lesezugriff, den die Portal Web API unter den Berechtigungs-Scopes Contact und Account als Known Issue dokumentiert. Server Logic setzt die Abfrage über den serverseitigen Dataverse-Connector ab, nicht über die Anfragepipeline der Portal Web API, damit ist dieses Problem hier vom Tisch.

Aufruf aus der Seite, on demand

Der Client ruft die Logik über ihren Namen unter /_api/serverlogics/<name> auf. Nutzen Sie den safeAjax-Wrapper des Portals, damit das Anti-Forgery-Token mitgeschickt wird:

webapi.safeAjax({
  type: "GET",
  url: "/_api/serverlogics/installation-products",
  contentType: "application/json",
  success: function (res) {
    // res.data enthält die Server-Logic-Antwort; parsen und rendern
  }
});

Das hängen Sie an einen Zeilen-Aufklapp-Handler oder einen Detail-Button. Nichts von der Abfrage liegt im Browser: Der Client sieht einen benannten Endpunkt und ein Ergebnis, nicht die Tabellennamen oder den Optionsstring. (Sie können Logik auch aus Liquid mit dem Tag {% serverlogic %} aufrufen, aber das läuft beim Seitenaufbau und bringt genau das Vorladen zurück, das Sie vermeiden wollten.)

Sicherheit: berechtigungsgebunden, und die Autorisierung ist Ihre Aufgabe

Server Logic läuft im Sicherheitskontext des Aufrufers und respektiert dessen Web Role und Tabellenberechtigungen. Das hat eine bequeme und eine scharfe Seite.

Die bequeme Seite: Ein nicht angemeldeter Besucher, oder einer, dessen Web Role keine Leseberechtigung auf den beteiligten Tabellen hat, bekommt nichts zurück. Die Leeres-Ergebnis-Falle aus dem FetchXML-Beitrag gilt auch hier. Wenn der Aufruf nichts liefert, prüfen Sie zuerst, als wer die Seite läuft, bevor Sie den Code auseinandernehmen.

Die scharfe Seite: berechtigungsgebunden heißt nicht sicher. Sobald Sie einen Parameter vom Client annehmen, etwa einen Entity-Set-Namen oder eine Datensatz-ID, tragen Sie die Autorisierungsentscheidung. Validieren Sie jede Eingabe, geben Sie clientgelieferte Werte niemals ungeprüft in eine Abfrage, und erzwingen Sie Tabellenberechtigungen (oder eine gleichwertige Prüfung) für die konkret betroffenen Datensätze. Serverseitig heißt nicht automatisch vertrauenswürdig.

Grenzen, die Sie vorher kennen sollten

  • Kein fetch, eval, require; unsichere Muster sind blockiert. Für externe Systeme nutzen Sie den bereitgestellten HttpClient, und ein Administrator kann externe HTTP-Aufrufe ganz abschalten.
  • Die Ausführung hat ein Timeout: standardmäßig 120 Sekunden, maximal 240 Sekunden. Server Logic ist für fokussierte Operationen gedacht, nicht für lange Batch-Läufe.
  • Der Aufruf aus Liquid mit {% serverlogic %} verlängert den Seitenaufbau und untergräbt damit das On-demand-Ziel. Bleiben Sie bei Client-Aufrufen, wenn Sie Reaktionsschnelligkeit wollen.

Welcher Weg für welche Aufgabe

Aufgabe Empfohlener Weg
Lesen N:M, Liste beim Seitenaufbau sichtbar Liquid FetchXML (link-entity / intersect)
Lesen N:M, on demand (Zeile aufklappen, Detailpanel) Server Logic + Server.Connector.Dataverse ($expand)
Schreiben N:M (verknüpfen / trennen) Portal Web API $ref (POST / DELETE)
Lesen 1:N / N:1 Portal Web API $expand (eine Ebene) oder Liquid

FetchXML und Server Logic sind weniger Konkurrenten als zwei Zeitpunkte desselben Lesezugriffs: vorgeladen gegen on demand. Entscheiden Sie danach, wann der Nutzer die Daten wirklich braucht, und halten Sie die Autorisierungsdisziplin für beide gleich streng.

Verwandte Artikel

Quellen

Tino Rabe

Tino Rabe

Power Pages Spezialist · Former Microsoft MVP

Power Pages Spezialist, former Microsoft MVP. Ich unterstütze Unternehmen bei sicheren Kundenportalen: vom Architektur-Workshop über Coaching bis zum Security-Audit.

Wann wurde Ihr Portal zuletzt unabhängig geprüft?

Security-Audit zum Festpreis, oder einfach erstmal sprechen.

Termin buchen