Power Pages è la soluzione di Microsoft Power Platform per costruire siti web esterni (rivolti a clienti, partner o cittadini) che leggono e scrivono dati direttamente in Microsoft Dataverse. Il motore di rendering delle pagine è Liquid, un linguaggio di template open source (nato in Ruby) eseguito server-side: consente di interrogare Dataverse e di iniettare dati e logica di presentazione nell’HTML prima che la pagina raggiunga il browser.

Liquid: cos’è e dove vive

Liquid usa tre costrutti principali:

  • Output {{ ... }} per stampare valori (es. {{ user.fullname }}).
  • Tag {% ... %} per la logica (cicli, condizioni, query).
  • Filtri {{ value | filter }} per trasformare l’output (es. | date: 'dd/MM/yyyy').

Liquid si scrive dentro i web template (componenti riutilizzabili di markup), nei content snippet, oppure nel campo Copy delle web page. I web template si compongono tramite ereditarietà: un template figlio dichiara {% extends 'Layout' %} e riempie i block definiti dal genitore. Questo pattern è centrale per costruire layout coerenti e header/footer condivisi.

Oggetti di contesto

Liquid espone oggetti globali che riflettono lo stato della sessione e del sito: user (il contatto autenticato o vuoto se anonimo), page, website, request, settings, sitemarkers e snippets. Sono la via idiomatica per personalizzare i contenuti in base a chi sta navigando.

Interrogare Dataverse con i Liquid tag

Per portare dati Dataverse in pagina esistono tag dedicati:

  • entitylist / entityview: caricano una list configurata nell’app di gestione (colonne, viste, filtri, paging) e permettono di renderizzarla con markup custom invece del componente low-code standard.
  • entityform / webform: incorporano un basic form o un multistep form progettato nel design studio.
  • fetchxml: esegue una query FetchXML arbitraria per scenari non coperti dalle viste predefinite. Esempio:
{% fetchxml myquery %}
<fetch top="5">
  <entity name="contact">
    <attribute name="fullname" />
  </entity>
</fetch>
{% endfetchxml %}
{% for c in myquery.results.entities %}
  {{ c.fullname }}
{% endfor %}

Esiste anche l’oggetto entities['nome_tabella'][guid] per leggere un singolo record per ID.

Componenti low-code vs Liquid custom

La scelta architetturale ricorrente all’esame è: usare List e Form low-code oppure scrivere Liquid?

  • List e Basic/Multistep Form (low-code): si configurano nel design studio, offrono search, paging, sort, azioni CRUD, validazioni e integrazione automatica con le table permission. Vanno preferiti quando lo scenario è coperto out-of-the-box: massimizzano manutenibilità e riducono codice.
  • Liquid custom (entitylist/fetchxml): da scegliere quando servono layout, aggregazioni o markup non ottenibili dai componenti standard — ad esempio una vista a card, un raggruppamento particolare o dati combinati da più tabelle. Il costo è maggiore complessità e responsabilità sul rendering.

Regola pratica: low-code prima, Liquid quando il low-code non basta.

Il ruolo delle table permission

Punto cruciale e sempre presente: Liquid non aggira la sicurezza. Ogni query (entitylist, fetchxml, entities[...]) rispetta le table permission configurate e i web role assegnati al contatto. Se un utente non ha permessi di lettura su una tabella, la query Liquid non restituirà quei record, indipendentemente da come è scritto il template. Per esporre dati occorre creare la table permission corretta (scope: Global, Contact, Account, Self) e collegarla al web role appropriato.

Inoltre le table permission richiedono le column permission per governare l’accesso a singoli campi.

Liquid è server-side, non JavaScript

Liquid viene valutato una sola volta, sul server, al momento della generazione della pagina. Non reagisce a eventi del browser, non aggiorna il DOM e non gestisce interattività client (validazioni dinamiche, chiamate on-click, aggiornamenti live). Per quella logica servono JavaScript lato client e le Web API di Power Pages (chiamate REST verso Dataverse). Liquid e JavaScript sono complementari, non alternativi.

Trappole tipiche d’esame

  • Scenario: una pagina Liquid con fetchxml non mostra alcuni record ai clienti. → Risposta giusta: mancano/insufficienti le table permission per il web role; Liquid rispetta sempre la sicurezza, non la aggira.
  • Scenario: serve validazione dinamica di un campo mentre l’utente digita. → Risposta giusta: usare JavaScript + Web API, non Liquid (che è server-side e non reattivo).
  • Scenario: elenco di record con paging, ricerca e azioni CRUD standard. → Risposta giusta: usare un List (basic form/multistep) low-code, non Liquid custom.
  • Scenario: layout a card personalizzato con dati aggregati da più tabelle. → Risposta giusta: entitylist/fetchxml in un web template, quando i componenti low-code non coprono il requisito.
  • Scenario: personalizzare il contenuto in base all’utente autenticato. → Risposta giusta: usare l’oggetto user e le condizioni Liquid {% if user %}, ricordando che per gli anonimi user è vuoto.