Become a member!

DelphiMVCFramework 3.5 RC7 entra nel Project Manager di Delphi e parla con gli agenti AI

🌐
Questo articolo è disponibile anche in altre lingue:
🇬🇧 English  •  🇪🇸 Español  •  🇩🇪 Deutsch  •  🇧🇷 Português  •  🇫🇷 Français

DelphiMVCFramework, il framework open source REST e web per Delphi

Cosa è cambiato in DelphiMVCFramework dopo la RC6? Il lavoro sulla 3.5 si è concentrato su come crei e fai crescere un progetto, dentro l'IDE di Delphi e insieme agli agenti AI. Questa volta te lo mostro con gli screenshot.

DelphiMVCFramework 3.5.0-silicon RC7 è una release candidate, non la 3.5.0 definitiva: le funzionalità sono quelle che vedi qui, e il tag stabile arriva dopo che la RC avrà girato su macchine diverse dalla mia.

La RC6 è del 23 agosto, e il post che la annunciava parlava di host, Minimal API e serializzatore in streaming. La RC7 è uscita il 22 settembre. Dopo, su master, sono arrivate due novità per il lavoro di tutti i giorni su un progetto. Un menù DMVCFramework nel Project Manager di Delphi crea controller, gruppi di rotte e viste e li registra nel progetto. I file per gli agenti AI danno al tuo assistente le regole e i sorgenti del framework, così non scrive l’API a memoria. Poi c’è il resto: Swagger UI con OpenAPI 3, le pagine web generate, QUERY, ProblemDetails.

Qui sotto trovi un giro veloce, quasi tutto per immagini. Ogni argomento ha il suo capitolo nella guida ufficiale, seconda edizione, con il codice completo e le spiegazioni che in questo post salto.


Cosa sta dove

Tutto quello che vedi qui appartiene alla RC7: è la versione che il wizard scrive nei progetti generati (3.5.0-silicon-rc7, la trovi anche negli screenshot). Una parte però non è ancora nello zip del tag:

  • Nella RC7 (tag v3.5.0-silicon-rc7): il metodo HTTP QUERY, la revisione di sicurezza con i suoi default nuovi, i limiti del server WebSocket, le correzioni per HTTP.sys, SQL Server e Delphi 13.2.
  • Su master, dopo la RC7: tutto il resto. Il menù nel Project Manager, i file per gli agenti AI, il wizard con OpenAPI 3, le pagine web generate, il sample con i form, ProblemDetails. Per averli clona master.

Gli screenshot qui sotto vengono da master.


Un menù DMVCFramework nel Project Manager

In Delphi 12 e 13, clic destro su un progetto DelphiMVCFramework nel Project Manager, e c’è un sottomenù DMVCFramework:

Il menù DMVCFramework nel Project Manager di Delphi 13, con la voce New REST Controller

Scegli New REST Controller…, scrivi il nome, e il resto si riempie da solo: il segmento di URL e la classe del modello a cui viene legato il body delle richieste.

La finestra New REST controller con Name Orders, URL segment orders e Model class TOrder

Premi OK e il menù crea Controllers.OrdersU.pas, lo aggiunge al progetto e lo registra in EngineConfigU.pas: la unit nella uses e AEngine.AddController(TOrdersController) accanto agli altri controller. Le modifiche passano dal buffer dell’editor, quindi un Ctrl+Z le annulla.

EngineConfigU.pas nell’IDE dopo l’inserimento di Controllers.OrdersU nella uses

Questo è il controller generato, così come esce dal menù in un progetto che ha la documentazione OpenAPI attiva:

type
  TOrder = class
  private
    fID: Integer;
    fName: string;
  public
    property ID: Integer read fID write fID;
    [MVCRequired]
    property Name: string read fName write fName;
  end;

  [MVCPath('/api/orders')]
  [MVCSWAGDefaultModel(TOrder, 'Order', 'Orders')]
  [MVCSWAGDefaultSummaryTags('Orders')]
  TOrdersController = class(TMVCController)
  public
    [MVCPath]
    [MVCHTTPMethod([httpGET])]
    [MVCSwagSummary(TSwaggerConst.USE_DEFAULT_SUMMARY_TAGS, 'List orders', 'getOrders')]
    // last argument: OkResponse renders the body as {"data": ...}
    [MVCSwagResponses(200, 'Success', SWAGUseDefaultControllerModel, True, True)]
    function GetAll: IMVCResponse;

    [MVCPath('/($ID:int)')]
    [MVCHTTPMethod([httpGET])]
    [MVCSwagSummary(TSwaggerConst.USE_DEFAULT_SUMMARY_TAGS, 'Get one', 'getOrder')]
    [MVCSwagResponses(200, 'Success', SWAGUseDefaultControllerModel, False, True)]
    [MVCSwagResponses(404, 'Not found')]
    function GetByID(ID: Integer): IMVCResponse;

    // the body is bound to Item and validated (422 on failure); the framework frees it
    [MVCPath]
    [MVCHTTPMethod([httpPOST])]
    [MVCSwagSummary(TSwaggerConst.USE_DEFAULT_SUMMARY_TAGS, 'Create', 'createOrder')]
    [MVCSwagParam(plBody, 'Item', 'The item to create', SWAGUseDefaultControllerModel)]
    [MVCSwagResponses(201, 'Created')]
    [MVCSwagResponses(422, 'Validation failed')]
    function CreateItem([MVCFromBody] Item: TOrder): IMVCResponse;
    ...

Il body arriva già deserializzato in Item e già validato: senza name la richiesta non entra nemmeno nell’action e il client riceve un 422. Lo schema delle risposte viene dalla classe del modello: con l’ultimo argomento di MVCSwagResponses il documento descrive anche l’involucro {"data": ...} che OkResponse aggiunge. Gli attributi MVCSwag* ci sono solo se il progetto pubblica un documento OpenAPI, ed è per questo che Orders e il suo modello compaiono in Swagger UI senza che io abbia scritto una riga: lo vedi più sotto.

Il menù mostra solo quello che il progetto può ospitare. In un progetto Minimal API il controller non avrebbe senso, e infatti la voce è un’altra:

Il menù DMVCFramework in un progetto Minimal API, con la voce New Minimal API Route Group

New Minimal API Route Group… crea OrdersRoutesU.pas con una procedura MapOrdersRoutes (body legati per tipo con MapPost<TOrder> e MapPut<Integer, TOrder>) e aggiunge la chiamata in fondo a ConfigureRoutes. Le altre due voci sono New Web Controller and View… e New TemplatePro View…, e compaiono solo se il progetto ha una cartella delle viste. Nelle versioni di Delphi precedenti alla 12 il menù non c’è.


Un progetto che nasce con le skill giuste

Se scrivi codice con Claude Code, Codex, Cursor o Gemini, un agente che non conosce DelphiMVCFramework si inventa nomi di metodi plausibili, oppure usa quelli di una versione vecchia, e il compilatore te lo dice solo dopo.

Con la RC7 ogni nuovo progetto DelphiMVCFramework nasce già pronto per l’agente: il wizard ci mette dentro le skill adatte a quel tipo di progetto, prese dalla stessa linea del framework che stai usando. Sono le best practice scritte per chi sviluppa con DelphiMVCFramework, divise per argomento:

  • Delphi: il linguaggio e la RTL, le differenze fra versioni, la gestione della memoria, stringhe, generics, thread; più una skill di code review su warning, analisi statica e memory leak.
  • DelphiMVCFramework: controller, ActiveRecord, validazione, dependency injection, middleware, i tre host, .env.
  • Sicurezza: le regole per ogni endpoint che riceve input dal client.
  • Test: test di integrazione con DUnitX.
  • Minimal API, web application, interfaccia, JSON-RPC: quando il progetto le usa.
  • HTMX: la documentazione ufficiale, organizzata per l’agente.

Il vantaggio lo vedi dalla prima richiesta. Senza skill e senza AGENTS.md, ogni sessione con l’agente comincia spiegandogli il progetto e il framework, e prosegue correggendo il codice che ha scritto a memoria: un metodo che non esiste, un pattern di una versione vecchia, un oggetto liberato due volte. Con il progetto generato dal wizard, l’agente sa già com’è fatto il progetto, dove stanno i sorgenti del framework e come si scrive un controller, un’entità ActiveRecord o una pagina HTMX in DelphiMVCFramework 3.5. Quel tempo lo risparmi a ogni sessione.

C’è anche la sicurezza. Fra le skill installate in ogni progetto c’è dmvcframework-security, con le regole per qualunque endpoint che riceve input dal client: controllo degli accessi, mass assignment, SQL injection, XSS, CSRF, path traversal e upload, JWT, segreti e messaggi d’errore, più una checklist da passare prima che un endpoint vada in produzione. L’agente la legge prima di scrivere un endpoint, quindi il codice che ottieni tende a essere più sicuro di quello che scriverebbe partendo da zero.

Le skill vivono in un repository a parte, con un branch per ogni linea del framework, e si aggiornano indipendentemente dalle release: quando esce una versione nuova di una skill, update_ai_skills.bat nella cartella del progetto la porta dentro.

L’opzione sta nella pagina Project Options, AI coding agent files and skills, ed è attiva di default in tutti i preset. Le skill vengono scaricate mentre il wizard crea il progetto, con una barra di avanzamento che puoi annullare; se non ti servono, togli la spunta.

La pagina Project Options del wizard con l’opzione AI coding agent files and skills

Con l’opzione accesa il wizard scrive nella cartella del progetto un AGENTS.md con i fatti del progetto, più CLAUDE.md e GEMINI.md che lo importano. Poi scarica in .claude\skills le delphi-ai-skills adatte a quel tipo di progetto, dal branch che corrisponde alla versione del framework (dmvc-3.5 per questa). Questo è l’AGENTS.md di un progetto RESTful API generato dalla suite di test del wizard, che lo chiama TestProject:

# TestProject

DelphiMVCFramework 3.5.0-silicon-rc7 project, generated by the DMVCFramework IDE wizard.

- `TestProject.dproj` builds the executable into `bin\`, next to `bin\.env` (configuration and secrets: never commit real values).
- Build from the command line: `rsvars.bat`, then `msbuild TestProject.dproj /p:Config=Debug /p:Platform=Win32`.

## Skills

Before writing Delphi or DelphiMVCFramework code, read the skill for the task. They target DelphiMVCFramework 3.5.x; `update_ai_skills.bat` downloads or refreshes them.

- `.claude/skills/delphi/SKILL.md` - the language and the RTL: version gating, lifetime, strings, generics, threading
- `.claude/skills/delphi-code-smells/SKILL.md` - code review: compiler warnings, static analysis, memory leaks
- `.claude/skills/dmvcframework/SKILL.md` - controllers, ActiveRecord, validation, DI, middleware, servers, dotEnv
- `.claude/skills/dmvcframework-security/SKILL.md` - REQUIRED for any endpoint taking client input
- `.claude/skills/dmvcframework-testing/SKILL.md` - DUnitX integration tests

Do not write Delphi or DelphiMVCFramework code from memory: the API names in these files are authoritative.

<!-- delphi-local-sources -->
DelphiMVCFramework checkout: C:\DEV\dmvcframework   (sources/ + samples/)
Delphi RTL/VCL source: C:\Program Files (x86)\Embarcadero\Studio\37.0\source   (CompilerVersion 37.0)
<!-- /delphi-local-sources -->

L’ultimo blocco dice all’agente dove stanno, sul tuo disco, i sorgenti del framework e della RTL: quando ha un dubbio su un nome va a leggere il codice vero.

Quali skill vengono installate dipende dal progetto. delphi, delphi-code-smells, dmvcframework, dmvcframework-security e dmvcframework-testing ci sono sempre; un progetto Minimal API aggiunge dmvcframework-minimal-api, una web application dmvcframework-webapp e dmvcframework-ui, con HTMX anche htmx-skill, un servizio JSON-RPC dmvcframework-jsonrpc. Se durante la creazione il download non riesce, il progetto viene creato lo stesso, con un warning, e update_ai_skills.bat completa l’installazione appena hai la rete.


Il wizard: documentazione API e chiave JWT

Nella pagina Features del preset Custom c’è un’opzione nuova, API documentation (OpenAPI 3). Negli altri preset non la vedi perché è già decisa: è attiva per RESTful API, Minimal API RESTful e Full-Stack.

La pagina Features del wizard DelphiMVCFramework con l’opzione API documentation (OpenAPI 3)

Con l’opzione attiva il wizard scarica la release ufficiale di Swagger UI (5.33.0, verificata con SHA-256) in bin\www\swagger mentre crea il progetto. Se sei offline il progetto viene creato lo stesso e in quella cartella trovi un README con i passi per scaricarla a mano. Il documento viene pubblicato solo se il .env contiene dmvc.openapi.enabled=true: il .env generato lo contiene, quello di produzione no, e in produzione la documentazione non esce.

I progetti con JWT adesso hanno nel .env una JWT_SECRET tutta loro, 384 bit dal generatore crittografico del sistema, diversa a ogni generazione. Il .gitignore generato esclude già il .env.


Swagger UI con OpenAPI 3

Questo è il progetto generato con il preset RESTful API, a cui ho aggiunto il controller Orders con il menù appena visto. Lo avvii, apri http://localhost:8080/swagger e trovi questo:

Swagger UI che mostra il documento OpenAPI 3 di un progetto DelphiMVCFramework a controller

Il middleware Swagger, quello che usi da anni, adesso produce anche OpenAPI 3. Il documento lo costruisce SwagDoc, la libreria inclusa nel framework, e il supporto a OpenAPI 3 in SwagDoc l’ha scritto Marcelo Jaloto (PR #916): grazie Marcelo! Il formato si sceglie con un nuovo ultimo parametro, ASpecVersion, che di default resta Swagger 2.0, quindi chi aggiorna non vede cambiare niente. Il progetto generato lo registra così:

AEngine.AddMiddleware(TMVCSwaggerMiddleware.Create(AEngine, LSwaggerInfo, '/openapi.json',
  JWT_DEFAULT_DESCRIPTION, False, '', '', '', [psHTTP], False, ssvOpenAPI3));
AEngine.AddMiddleware(TMVCStaticFilesMiddleware.Create('/swagger',
  TPath.Combine(TPath.Combine(AppPath, 'www'), 'swagger')));

Funziona tutto quello che funzionava con Swagger 2.0: sicurezza JWT e basic, MVCSwagAuthentication, MVCSWAGDefaultModel, i percorsi CRUD di TMVCActiveRecordController. Lo schema JWT è http/bearer, quindi nella finestra Authorize incolli il token così com’è. Il server nel documento è relativo, e “Try it out” chiama l’origine che ha servito il documento, anche dietro un proxy.

L’operazione POST /api/orders in Swagger UI, con il body richiesto e le risposte 201 e 422

Nei progetti Minimal API il wizard registra invece il filtro OpenAPI(...) di MVCFramework.OpenAPI3, che genera un documento OpenAPI 3.1 dalle rotte lambda e lo pubblica allo stesso URL, con la stessa Swagger UI.

I campi TDate, TDateTime e TTime adesso sono descritti con i formati standard date, date-time e time, quindi un client rigenerato dal documento ottiene tipi data invece di stringhe (anche questo arriva con la PR di Marcelo). Gli attributi di documentazione dei campi adesso si chiamano tutti MVCSwag*: MVCFormat, MVCMinimum e MVCMaximum compilano ancora, con un warning, fino alla 4.0.


Le web application generate

Il preset Web Application adesso parte da un’interfaccia più completa: intestazione di pagina, un pannello con lo stato del server aggiornato via HTMX, una lista “Start here” con i primi passi, tema chiaro e scuro. Il codice generato però è sempre il minimo: l’esempio con tabella e form è finito in un sample a parte, di cui parlo più sotto.

La home page di una web application DelphiMVCFramework generata dal wizard, tema scuro

La stessa home page con il tema chiaro

Il preset Minimal API WebApp genera le stesse pagine, con le rotte lambda al posto dei controller. Qui sotto c’è la pagina di login dopo un tentativo sbagliato: lo username resta nel campo, la password no. Il form è legato a una classe, e la pagina lo rimostra da lì.

La pagina di login di una Minimal API WebApp dopo credenziali errate


Tabelle e form con HTMX: webapp_htmx_forms

L’esempio della tabella People, che prima stava nel progetto generato, è diventato un sample a sé: samples/webapp_htmx_forms. Lì ci sono ricerca, filtri, ordinamento e i form completi, senza appesantire ogni progetto nuovo.

La tabella si filtra, si cerca e si ordina per colonna. Con HTMX il server restituisce solo il frammento della tabella e la pagina non si ricarica; l’action decide se mandare la pagina intera o il frammento, e imposta Vary: HX-Request perché lo stesso URL ha due body diversi.

La tabella People del sample webapp_htmx_forms filtrata con la ricerca analyst

I form di inserimento e modifica usano tutte le macro della libreria di form di TemplatePro (bin/templates/lib/forms_bootstrap5.tpro, che il wizard copia in ogni progetto TemplatePro) e vengono validati sul server con gli attributi di DelphiMVCFramework e TMVCValidationEngine. Se qualcosa non va, il form torna indietro con stato 422, i valori che hai scritto e il messaggio accanto al campo. Se va tutto bene, redirect alla tabella (Post/Redirect/Get), così un F5 non reinvia il form.

Il form New person rimostrato con errori di validazione su Name e Joined

Lato TemplatePro, la cache delle viste compilate adesso vive in memoria: con view_cache=true dopo la prima richiesta una vista non tocca più il disco. Se le modifichi mentre il server gira, dmvc.view_cache_check_changes=true rimette il controllo a ogni richiesta, layout e partial compresi.


Form generati con TemplatePro

Il form dello screenshot qui sopra viene dalla libreria di form di TemplatePro, forms_bootstrap5.tpro, che il wizard copia in bin/templates/lib in ogni progetto con le viste TemplatePro. La importi una volta in cima alla pagina e hai otto macro: form, input, textarea, select, checkbox, submit, actions e auto.

{{import "../lib/forms_bootstrap5.tpro" as f}}
{{call f.form(form_action)}}
{{>f.input("id", label="ID", readonly=true)}}
{{>f.input("name", label="Name", required=true)}}
{{>f.select("role", roles, label="Role", empty="Choose a role")}}
{{>f.input("projects", type="number", append="active")}}
{{>f.textarea("notes", label="Notes", rows=3)}}
{{>f.checkbox("remote", label="Works remotely")}}
{{>f.submit("Save")}}
{{endcall}}

Ogni macro legge il valore del campo da formModel e il messaggio di errore da formErrors, due variabili che imposti nell’action. Il modello può essere un oggetto, il record corrente di un dataset, un oggetto JSON o un dizionario. Se per quel campo c’è un errore, il controllo prende la classe is-invalid e il messaggio compare sotto: è quello che vedi nel form rimostrato con il 422. Valori e messaggi sono sempre HTML-escaped, le date vengono formattate per i controlli date, time e datetime-local, e con attrs passi una mappa di attributi extra, per esempio quelli di HTMX. La stessa pagina serve per creare e per modificare: cambiano solo il modello e l’action.

Poi c’è auto, che genera tutto il form da solo:

{{call f.form("/forms", attrs=formattrs)}}
  {{>f.auto(demo)}}
  {{>f.submit("Save")}}
{{endcall}}

Un form generato da f.auto a partire dalle proprietà di un oggetto Delphi

auto percorre i campi del modello (model.@@fields: le proprietà di un oggetto o i campi di un dataset) e sceglie il controllo dal tipo. Una stringa diventa un campo di testo con maxlength preso dalla dimensione, un intero un campo numerico, un TDate un date picker, un TDateTime un datetime-local, un TTime un campo ora, un Boolean una checkbox, un memo una textarea. Una proprietà senza setter diventa readonly. L’etichetta viene dal nome: FullName diventa “Full name”. Con exclude togli i campi che non vuoi mostrare.

Se il modello è un’entità TMVCActiveRecord, aggiungi alla uses la unit MVCFramework.View.Renderers.TemplatePro.ActiveRecord (il wizard lo fa da solo nei progetti con ActiveRecord e TemplatePro). Da quel momento i campi seguono la mappatura di ActiveRecord e i validatori: [MVCRequired] diventa l’attributo required, [MVCMaxLength(n)] diventa maxlength. Per tutto il resto c’è TTProConfiguration.OnGetFieldMetadata, che ti permette di cambiare etichetta, tipo, visibilità e obbligatorietà di ogni campo. Il form completo con tutte le macro lo trovi nella pagina /forms del sample samples/wizard_showcase/web.


ProblemDetails più aderente alla RFC 7807

Le risposte di ProblemDetails(...) adesso seguono la RFC 7807 più da vicino: il problem object è l’intero body e il Content-Type è application/problem+json. Il 422 della Minimal API ha in più un membro errors, con il messaggio per ogni campo.

Questo è il gruppo di rotte Orders generato dal menù, in un progetto Minimal API: un POST senza name, poi un POST con un array al posto dell’oggetto.

$ curl -s -i -X POST http://localhost:8080/api/orders -H "Content-Type: application/json" -d "{\"id\":7}"
HTTP/1.1 422 Unprocessable Entity
Connection: keep-alive
Content-Type: application/problem+json; charset=UTF-8
Content-Length: 176
Date: Mon, 05 Oct 2026 15:22:03 GMT

{"type":"about:blank","title":"Unprocessable Content","status":422,"detail":"Validation failed for fields: Name","instance":"/api/orders","errors":{"Name":"Field is required"}}

$ curl -s -i -X POST http://localhost:8080/api/orders -H "Content-Type: application/json" -d "[1,2]"
HTTP/1.1 400 Bad Request
Connection: keep-alive
Content-Type: application/problem+json; charset=UTF-8
Content-Length: 163
Date: Mon, 05 Oct 2026 15:22:03 GMT

{"type":"about:blank","title":"Bad Request","status":400,"detail":"Body is not a valid JSON Object - Expected TJsonObject got TJsonArray","instance":"/api/orders"}

Un array dove serve un oggetto è un errore del client, quindi la risposta è un 400, sia nei controller con [MVCFromBody] sia nella Minimal API.


Il metodo HTTP QUERY

QUERY (RFC 10008) è sicuro e idempotente come GET, ma ha un body: la ricerca viaggia nel payload, non nell’URL, quindi non ha limiti di lunghezza e non finisce nei log di accesso, nelle cache dei proxy o nella cronologia del browser. Ne ho parlato per esteso in un post dedicato. Nella RC7 lo trovi nei controller, nella Minimal API (MapQuery) e in IMVCRESTClient (Query).

Il sample samples/routing fa la stessa ricerca due volte, con GET e con QUERY:

[MVCHTTPMethod([httpQUERY])]
[MVCPath('/customers/searches')]
[MVCConsumes(TMVCMediaType.APPLICATION_JSON)]
[MVCProduces(TMVCMediaType.APPLICATION_JSON)]
function SearchCustomersUsingQuery(
  const [MVCFromBody] Criteria: TCustomerSearch): TObjectList<TPerson>;
$ curl -s -i -X QUERY http://localhost:8080/api/customers/searches -H "Content-Type: application/json" -d "{\"searchtext\":\"rossi\",\"cities\":[\"rome\",\"milan\"],\"pricerange\":{\"min\":10,\"max\":90},\"orderby\":\"lastname\",\"page\":2}"
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json; charset=utf-8
Content-Length: 226
Date: Mon, 05 Oct 2026 17:22:01 GMT
Server: DMVCFramework
X-Powered-By: DMVCFramework 3.5.0-silicon-rc7

[{"firstname":"Daniele","lastname":"Teti","dob":"1975-05-02","married":false},{"firstname":"John","lastname":"Doe","dob":"1975-05-02","married":false},{"firstname":"Mark","lastname":"Rossi","dob":"1975-05-02","married":false}]

Prima di metterlo in produzione: per il CSRF trattalo come POST, non come GET. Il default di Access-Control-Allow-Methods del filtro CORS non lo include, e se un browser di un’altra origine deve chiamarlo devi passare la lista completa. E nel documento Swagger/OpenAPI non compare: lo slot query esiste solo in OpenAPI 3.2, e il framework salta il verbo invece di scrivere un documento non valido.


Sicurezza: default più sicuri

La RC7 contiene una revisione di sicurezza del ramo 3.5, e alcuni default adesso sono più sicuri. Se aggiorni da una versione precedente, questi sono quelli da conoscere:

  • X-HTTP-Method-Override non è più supportato. Riscrivere il verbo di una richiesta spetta al reverse proxy o al web server che sta davanti all’applicazione.
  • IMVCRESTClient e TMVCSSEClient accettano solo certificati validi. Per un test contro un host con certificato self-signed c’è MVCRESTClientAcceptInvalidCertificates := True.
  • Il cookie di sessione è HttpOnly di default, e da Delphi 11 ha SameSite=Lax. Secure è un parametro nuovo, spento di default perché accenderlo romperebbe ogni setup di sviluppo in HTTP; i progetti generati lo leggono da SESSION_COOKIE_SECURE nel .env.
  • Oltre max_request_size la risposta è 413 su tutti gli host, con lo stesso comportamento su Indy, HTTP.sys e WebBroker.
  • Più protezione contro i JSON malevoli: il parser rifiuta i documenti costruiti per mettere in difficoltà il server.
  • [MVCMaxLength(n)] e [MVCPattern(...)] validano sempre, in qualunque ordine compaiano le unit nella uses. Questo è su master: se hai modelli con quegli attributi, dopo l’aggiornamento li trovi validati.

La lista completa, con il motivo di ogni modifica, è nella sezione Security del changelog.


Il resto, in breve

  • Rotte controllate alla registrazione. I tipi dei parametri (int, int64, float, bool, guid, date, time, datetime, sqids) vengono da una sola funzione per i controller e per la Minimal API; time e datetime accettano solo ISO 8601 e si legano a parametri TTime e TDateTime. Un tipo sconosciuto, un parametro senza nome o un catch-all fuori posto fanno fallire la registrazione: il server non parte, invece di rispondere 404 per sempre a una rotta scritta male.
  • Il body si può restituire nella risposta. Result := OkResponse(Person) con [MVCFromBody] Person, o Ok(Item) nella Minimal API: la risposta prende in carico l’oggetto e lo libera dopo il render.
  • HTTP.sys risponde a PATCH, SEARCH e agli altri verbi che il kernel non interpreta da solo.
  • Server WebSocket: quattro limiti configurabili su handshake e dimensione dei frame, attivi di default (PR #915).
  • SQL Server: foRefresh restituisce la riga dopo i trigger, Insert e Update funzionano su tabelle con trigger, il locking ottimistico viene rilevato anche dietro un trigger senza SET NOCOUNT ON (diagnosi di Flavio Basile).
  • Delphi 13.2: il framework compila anche sull’ultimo aggiornamento di Delphi 13 (#917).
  • TemplatePro accetta più tipi di campo dei dataset e non mostra più come negativi i valori unsigned grandi (contributo di Patrick Premartin).

Su Patreon: articoli e video su queste funzionalità

Per i supporter su Patreon arriveranno articoli e video dedicati proprio a queste novità: il menù del Project Manager, le skill per gli agenti AI, la documentazione OpenAPI generata. Come usarle nel lavoro di tutti i giorni, passo per passo.

Se usi DelphiMVCFramework a livello professionale, ti chiedo di supportare il progetto. È un investimento sul tuo business: il framework su cui lavori continua a crescere, e da supporter puoi orientarne i prossimi sviluppi. In più hai accesso ai contenuti formativi dedicati, ai gruppi Discord riservati con supporto privilegiato e al supporto via email prioritario.


Provarla

Per la RC7, scarica lo zip dalla pagina di release e aggiungi sources al library path. Per tutto il resto clona master e installa il package dmvcframeworkDT della tua versione di Delphi: i preset compaiono in File > New > Other, sotto Delphi > DelphiMVCFramework, e il menù nel Project Manager arriva con lo stesso package.

Se qualcosa non torna, apri una issue su GitHub. Siamo ancora in fase di release candidate, ed è adesso che una segnalazione diventa una correzione nella 3.5.0.


Risorse

PATREON Community

Enjoy!

– Daniele Teti

Fatti chiave
  • Argomento: le novità di DelphiMVCFramework 3.5.0-silicon dopo la RC6 (23 agosto 2026): la RC7 (tag v3.5.0-silicon-rc7, 22 settembre 2026) e quello che è su master al 5 ottobre 2026 (stessa versione, 3.5.0-silicon-rc7). È una release candidate, non la 3.5.0 definitiva.
  • Nella RC7: metodo HTTP QUERY (RFC 10008) con [MVCHTTPMethod([httpQUERY])], MapQuery nella Minimal API e Query in IMVCRESTClient; HTTP.sys smette di trattare SEARCH e altri verbi come GET; una revisione di sicurezza con nuovi default (sessione HttpOnly, 413 su ogni host oltre max_request_size, protezione contro JSON malevoli, X-HTTP-Method-Override ignorato, certificati non validi rifiutati da IMVCRESTClient); limiti sul server WebSocket; correzioni per SQL Server e per Delphi 13.2.
  • Su master dopo la RC7: OpenAPI 3 dal middleware Swagger (ssvOpenAPI3), opzione "API documentation (OpenAPI 3)" nel wizard con Swagger UI 5.33.0 scaricata alla creazione del progetto e pubblicata su /swagger quando .env imposta dmvc.openapi.enabled=true; chiave JWT generata nel .env; file per agenti AI (AGENTS.md, CLAUDE.md, GEMINI.md e le delphi-ai-skills) come opzione del wizard, attiva di default in tutti i preset.
  • Menù "DMVCFramework" nel Project Manager di Delphi 12 e 13: nuovo controller REST, controller web con vista, gruppo di rotte Minimal API, vista TemplatePro; la unit viene registrata da sola (AddController o Map<Name>Routes) e i body sono legati a una classe modello con [MVCFromBody] o MapPost<TModel>; con OpenAPI attivo il modello compare in Swagger UI.
  • Web application: interfaccia generata più completa (Bootstrap 5.3, tema chiaro e scuro), Minimal API WebApp con le stesse pagine, nuovo sample samples/webapp_htmx_forms con tabella filtrabile via HTMX e form validati lato server con risposta 422.
  • ProblemDetails è un body RFC 7807 vero (application/problem+json); il 422 della Minimal API ha un membro errors campo per campo; un body JSON del tipo sbagliato risponde 400 invece di 500.
  • Le novità sono approfondite nella guida ufficiale di DelphiMVCFramework, seconda edizione, su Leanpub.
  • Autore: Daniele Teti, creatore di DelphiMVCFramework.

Domande frequenti

Cosa c'è di nuovo in DelphiMVCFramework 3.5 dopo la RC6?
La RC7 (22 settembre 2026) ha aggiunto il metodo HTTP QUERY, una revisione di sicurezza con alcuni default cambiati, limiti sul server WebSocket e correzioni per HTTP.sys, SQL Server e Delphi 13.2. Su master, dopo la RC7, sono arrivati OpenAPI 3 e Swagger UI nel wizard, il menù DMVCFramework nel Project Manager di Delphi 12 e 13, i file per gli agenti AI (AGENTS.md e le delphi-ai-skills), pagine web generate più complete, il sample webapp_htmx_forms e ProblemDetails conforme a RFC 7807.
Come si attiva la documentazione OpenAPI 3 in un progetto DelphiMVCFramework?
Nei progetti nuovi basta l'opzione "API documentation (OpenAPI 3)" del wizard, attiva di default nei preset RESTful API, Minimal API RESTful, Full-Stack e Custom. Nei progetti esistenti a controller si passa ssvOpenAPI3 come ultimo parametro di TMVCSwaggerMiddleware o del filtro Swagger(...); nella Minimal API si usa il filtro OpenAPI(...) di MVCFramework.OpenAPI3. Il progetto generato pubblica /openapi.json e Swagger UI su /swagger solo se il file .env imposta dmvc.openapi.enabled=true.
In quali versioni di Delphi c'è il menù DMVCFramework nel Project Manager?
In Delphi 12 Athens e Delphi 13 Florence. Il menù compare con un clic destro su un progetto DelphiMVCFramework e mostra solo le voci adatte al tipo di progetto: controller REST e web nei progetti a controller, gruppo di rotte nei progetti Minimal API, viste TemplatePro dove esiste la cartella delle viste.
Dove sono spiegate nel dettaglio queste novità?
Nella guida ufficiale di DelphiMVCFramework, seconda edizione, disponibile su Leanpub. Il post mostra le novità con gli screenshot, la guida le tratta capitolo per capitolo.

Comments