*XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD...

40
Guida alla creazione di una Web Application in ASP.Net Forms 4.5+BootStrap 3+INSPINIA Admin theme + autenticazione Membership SQL Server. CheckList WorkFlow 4.5 Creato il 19/12/2014 Ultimo aggiornameno di questa guida: 03/02/2015 Autore: Fabio Guerrazzi Questa guida consiste nelle mie note prese durante lo studio di Asp.Net Forms 4.5 e gli altri pacchetti elencati nel titolo del presente documento. Qui troverai la struttura di una webapp denominata Citypost o SailWeb, diventata poi una app di produzione. Qui ci sono solo riferimenti tecnico/strutturali e non viene violata la proprietà intellettuale che appartiene a TDGroup s.p.a e Citypost. Oggi la web app si è evoluta molto. Queste sono solo le fondamenta su cui basa l’app in produzione. Introduzione Il sito è stato denominato CitypostWeb45, sviluppato su target Framework ASP.NET 4.5 Questa soluzione è stata necessaria in quanto sul cloud Windows Azure e WebMatrix esistevano basi di creazione WebApplication ASP.NET completi di autenticazione solo di questa versione. Ne sono state scaricate e provate altre, e questa ad oggi sembra l’unica che permettesse di lavorare su un sistema aperto, senza eccessivi User Control Microsoft o di terze parti. In breve, è risultato quello piu pulito e ordinato.

Transcript of *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD...

Page 1: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Guida alla creazione di una Web Application in ASP.Net Forms 4.5+BootStrap 3+INSPINIA Admin theme + autenticazione

Membership SQL Server. CheckList WorkFlow 4.5

Creato il 19/12/2014 Ultimo aggiornameno di questa guida: 03/02/2015

Autore: Fabio Guerrazzi

Questa guida consiste nelle mie note prese durante lo studio di Asp.Net Forms 4.5 e gli altri pacchetti elencati nel titolo del presente documento. Qui troverai la struttura di una webapp denominata Citypost o SailWeb, diventata poi una app di produzione. Qui ci sono solo riferimenti tecnico/strutturali e non viene violata la proprietà intellettuale che appartiene a TDGroup s.p.a e Citypost. Oggi la web app si è evoluta molto. Queste sono solo le fondamenta su cui basa l’app in produzione.

Introduzione Il sito è stato denominato CitypostWeb45, sviluppato su target Framework ASP.NET 4.5 Questa soluzione è stata necessaria in quanto sul cloud Windows Azure e WebMatrix esistevano basi di creazione WebApplication ASP.NET completi di autenticazione solo di questa versione. Ne sono state scaricate e provate altre, e questa ad oggi sembra l’unica che permettesse di lavorare su un sistema aperto, senza eccessivi User Control Microsoft o di terze parti. In breve, è risultato quello piu pulito e ordinato.

Page 2: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Le tecniche utilizzate sono state tratte da Professional ASP.NET 4.5 in C # and VB -nelly-.pdf Il PDF, di 88Mb e 1.444 pagine, contiente tutto quello che c’è da sapere su ASP.NET. Suggerisco di consultare questo file prima di qualsiasi ricerca su google perche c’è veramente tutto Caratteristiche principali Come preannuncia la home page del sito, lo strumento è stato pensato per suddividere le aree applicative vincolando ai propri dati di pertinenza gli utenti Citypost o Sailnet, e di globalizzarle per l’assistenza. L’assistenza vede e gestisce tutto il mondo, i singoli utenti solo le proprie informazioni. Il portale è a tema Responsive, ha 4 livelli di ridimensionamento automatico a seconda dello schermo o dispositivo che lo sta utilizzando e si adatta perfettamente a telefoni e tablet. E’ possibile autenticarsi con Google o ID Microsoft, Facebook o Twitter. I benefici di una autenticazione con account Social è che integrano la pubblicazione di notizie automatiche. Considerando che una buona parte degli utenti già oggi utilizza dispositivi mobili, il proprio device resta collegato in modo permanente. Il sistema è modulare, sia il motore di accesso ai database che alle risorse applicative vengono utilizzate solo se l’utente appartiene a quel contesto. Cioè evita di far caricare al sistema risorse di cui non ha bisogno. Il sistema di sicurezza utilizza le piu recenti tecnologie anti-intrusione. Installazione (non necessaria in fase di manutenzione ma come promemoria)

Di seguito gli step eseguiti per l’installazione base del sito

- Da Visual Studio 2012 New WebSite - Framework 4.5 - Project Type Sito Web Form ASP.NET - Il kit o template di VS installa automaticamente gli assemblies, i componenti grafici, layout

e operativi, su modello del 4.0, come mostrato nell’immagine sottostante

Page 3: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

- Sono stati sostituiti i temi e skin con bootstrap.css, bootstrap.js, Bootstrap è un prodotto opensource adottato dagli standard Google Inc.

- Gli elementi sono stati allineati al tema cerulean, visibili all’indirizzo http://bootswatch.com/cerulean/ (La pagina è stata salvata su disco, in caso di aggiornamento futuri, qui abbiamo la fotografia dello stile in uso a CitypostWeb45)

- Per includere BootStrap e jQeury, Modernizr, si va su Console Getione Pacchetti di Visual Studio

Page 4: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

- Dalla console NuGet digitare Get-Package –ListAvailable per ottenere l’elenco dei package disponibili (consiglio di farlo in un momento di inutilizzo del computer perche la lista è lunghissima, che comunque ho incluse nella cartella di Documentazione)

- Per il sito va eseguito Install-Package BootStrap per caricare la v3.0 di bootstrap - Va aggiornato jQuery, che il template installa la 1.8, mentre Install-Package jQuery

aggiorna alla 2.1.1 - Va installato Install-Package jQuery-validate

ASP.NET

Page 5: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Una volta installato il sito, deve essere configurato il dataprovider di default per la creazione del db dedicato alle policies ASP.NET. Per farlo è sufficiente indicare nel Web.Config la stringa di connessione DefaultConnection <add name="DefaultConnection" connectionString="Data Source=<ip>;Initial Catalog=dbLog;Persist Security Info=True;User ID=sa;Password=" providerName="System.Data.SqlClient"/> e dalle pagine ASP.Net Management(*) dire che il defaultDataProvider usa la DefaultConnection. Al primo avvio del sito, se questi 2 parametri sono stati impostati correttamente, il sistema crea automaticamente tutte le tabelle che gli servono per l’autenticazione. Dalla Home della nuova WebApp occorre registrarsi come admin e quindi si è loggati per le prime prove con questo utente.

(*) da Visual Studio 2013 ASP.Net Management non esiste piu, lo hanno tolto e non si sa con cosa gestire il Provider, le indicazioni trovate in rete a me non funzionano. Le ho rifatte a manina, pagina per pagina (gestione utenti, ruoli, associazioni, ecc)

Perchè ASP.NET 4.5 La ragione per cui è stata adottato il sistema di autenticazione integrato è solamente per questioni di sicurezza. Il framework 4.5 integra System.Web.Security che da questa versione si occupa autonomamente di validare le richieste processando filtri di sicurezza Anti-XSRF e DoS, fornisce token di sessione e la chiude nel caso in cui rilevi una condizione di intrusione. Inoltre il sistema di autenticazione ASP NET permette maggiori garanzie di allineamento futuro sulle criticità di sicurezza, che riguardino IIS, Windows Server, il Browser o il Framework stesso. Compatibilità Framework IIS e Server Nonostante il sito sia sviluppato su Framework 4.5, Windows 2003 IIS 6 con ASP.NET 4.0 dovrebbe supportare il deploy e la pubblicazione senza problemi. Questo perche ASP.NET 4.5 di fatto non esiste, è il framework ad essere avanzato di versione, e durante la pubblicazione copia le sue DLL, ma su IIS il pool di Applicazioni resta ASP.NET 4.0

Sistema di Autenticazione L’obiettivo principale pensando alle regole di autenticazione è stato quello di gestire un sistema piu semplice possibile da mantenere in termini di configurazione e programmazione. Non è stato facile, in quanto le casistiche sono ampie e gli elementi altrettanto, ma mi sono basato sul sistema Drupal che ho trovato piu che efficiente. La sfida è stato nel riprodurlo in ASP NET con il suo framework nativo, senza creare troppe tabelle o configurazioni specifiche sul web.config. Dovrei esserci riuscito. Il principio è semplice: A ciascun utente è associato uno o piu ruoli. A ciascun ruolo corrisponde uno o piu permessi. I permessi vincolano l’accesso a voci di menu, funzioni, pagine, files, cartelle

Page 6: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

System.Web.Security espone le sue proprie tabelle Users, Roles, Membership, Application e UsersInRoles. Io ho aggiunto la tabella Permessi, in cui aggiungo tutte le pagine o regole che voglio associare ad un ruolo. All’accesso vengono caricati i propri ruoli e i propri permessi. ASP.Net di suo non offre nessun automatismo di vsibilità o accesso alle informazioni delle pagine, vanno implementate da codice a seconda dei casi. , nell’esempio che segue, se l’utente non ha il ruolo Admin non fa il render della voce di menu sulla pagina e per l’utente finale non esiste fisicamente.

<% if (WebHelper.UserRuoli.Contains("Admin")) { %> <li> <a id="A2" runat="server" title="Gestisci i permessi" href="~/Account/Admin.aspx">Admin</a> </li> <% }; %>

ATTENZIONE: Quando si crea una nuova pagina, un nuovo menu o una nuova funzionalità, per default sarà visibile a tutti, Anonimi compresi. Se deve essere vincolata solo a determinati utenti, creare i records necessari nella tabella Permessi Ruoli di base e il loro utilizzo Admin, deve aver accesso a tutte le funzioni e pagine del sito, assume il ruolo di Redattore Redattore. Ha accesso a tutte le funzioni di gestione dati, ad esempio, combinato al ruolo SailNet vede TUTTE le agenzie, ecc Citypost. Ha accesso alle funzioni e pagine CityPost SailNet. Ha accesso alle funzioni e pagine SailNet Esempi: Un utente con ruoli Citypost e Redattore, vede e gestisce tutti gli utenti citypost ma non vede funzionalità SailNet Un utente con solo il ruolo SailNet vede esclusivamente la sua Agenzia, impostata da profilo.

Accesso ai dati di ASP.NET e manutezione policies ASP.NET da solo creato le tabelle seguenti, il server e catalog scelto è dbLog di pomezia: di sistema Tabella Descrizione

Si Users Raccoglie gli utenti ( campi IdUser e UserName) Si MemberShip Contiene un record per ogni utente con le proprie

informazioni sull’account (password, email, se è bloccato, date di accesso, login)

Si Applications Contiene le WebApp (noi ne usiamo una sola, la root del sito, da investigare l’utilità di uno split su piu app)

Si Profiles Contiene tutte le proprietà estese degli utenti, che sono

Page 7: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

definite nel Web.Config Si Roles Contiene i nomi dei Ruoi (IdRole, RoleName) Si UsersInRoles Contiene gli idUser e idRoles di abbinamento utenti/ruoli

No Permessi Contiene le pagine, cartelle, funzioni abbinate ai ruoli che in modo programmatico vengono usate nel codice

Tutte le tabelle di sistema sono normali tabelle SQL Server accessibili con gli strumenti SQL standard. I dati possono essere interrogati o modificati a mano, ma è opportuno che sia ASP Net a creare i records, in quanto genera le proprie Keys. Sul sito ho aggiunto un DHTML per l’accesso ai dati via LinQ e l’ho inserito per praticità, ma all’avvio della Web Application, il namespace System.Web.Security contiene già questi Datacontext con tutti i metodi per creazione, validazione, associazione e profilazione utenti. Accedendo con Admin sono a disposizione le pagine di amministrazione del sito, degli utenti e policies. Eseguire da li qualsiasi operazione di manutenzione.

Profilazione ASP.NET supporta coma base di campi uno standard di autenticazione, (nome utente, password, email) mentre nella realtà produttiva agli utenti devono poter essere associate informazioni aggiuntive, MS mette a disposizione una classe ProfileCommon, che è interamente programmabile. I campi aggiuntivi sono definiti nel Web.config, e gli stessi nella classe UserInfo. Successivamente, da codice, il namespace System.Web.Profile rende accessibili e modificabili queste proprietà insieme al contesto dell’utente. Vedi il Cap. 19 della giuda in pdf ASP.NET 4.5 C#

Autenticazione applicativa Una volta autenticato su ASPNet del sito e i ruoli corrispondono, il sistema deve effettuare l’autenticazione classica di CitypostWeb4 passando per LG_Utenti, LG_Profili, LG_Gruppi, ecc. Tra i campi di customizzazione profilo ho inserito l’id e password applicativo. IDAnagrafico AppPassword Se ad un utente viene assegnato il ruolo Citypost, il significato di questi due campi assumono UserName e pwd di LG_utenti, mentre se il ruolo è SailNet l’id deve corrispondere CodUnivoco di AnagraficaClienti in NORMBATCH che aggancia l’agenzia Se è validato l’utente ha accesso alle funzionalita Citypost o SailNet e viene reindirizzato sulla propria HomePage Nello specifico, l’autenticazione ASP stabilisce una connessione univoca, sicura, basata su crittografica e scambio di chiavi di sicurezza, quella applicativa stabilisce il comportamento sull’utilizzo delle pagine e delle funzioni:

Page 8: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

a) I ruoli Admin vengono sempre rediretti sulla Home di root del portale ed hanno la visibilità di tutte le funzioni di utlitià e sistema, controllo degli utenti, dei ruoli, dei permessi, stato del sito, analisi ecc. Dovrebbero esistere almeno 2 utenti con questo ruolo

b) I ruoli Redattore sono gli utenti che prestano assistenza a una o piu aree di lavoro e vedono tutti gli elementi. Un Redattore Sailnet accede all’elenco di tutte le agenzie ed ha accesso a tutte le funzioni operative di pertinenza globale o può scegliere di lavorare come se fosse l’agenzia selezionata. I Redattori dovrebbero essere solo attribuiti al personale Citypost o SailNet per le analisi e manutenzione della globalità dei contesti. Un utente Redattore con uno solo dei due ruoi applicativi viene reindirizzato sulla home contestuale, se ha entrambi gli ambienti viene reindirizzato come un Admin sulla Home principale da cui puo scegliere.

c) Né Admin né Redattori devono avere ID e PWD applicativa, in quanto gestiscono elenchi. d) I ruoli SailNet non Admin e non Redattore sono le utenze sul territorio, devono avere ID

Anagrafica impostata sul profilo, vengono rediretti sulla Home SailNet (/SailNet/Default.aspx), vedono e gestiscono solo le informazioni legate alla propria agenzia.

e) I ruoli CityPost non Admin e non Redattore sono i clienti CityPost, devono avere ID Anagrafica e password impostata sul profilo, vengono rediretti sulla Home CityPost (/Citypost/Default.aspx), vedono e gestiscono solo le informazioni legate alla propria utenza, con le stesse regole e filtri già esistenti su CitypostWeb4.

f) I ruoli CityPost NON vedono il loro vecchio ID utente e Password, come i SailNet NON vedono e non possono modificare il loro codice Agenzia. Sarà cura degli Admin associare ad ogni utente le credenziali gestionali. Vedi piu avanti “Messa in produzione” per come portare in massa le credenziali esistenti sul sito

g) I ruoli Membro al momento non implicano azioni particolari, non hanno accesso a nessuna area applicativa e vengono solo autenticati da Asp.Net. per uso futuro

h) Il ruolo Anonimo viene assegnato automaticamente all’utente Anonimo di sistema. Questo particolare utente corrisponde all’identificativo che prendono gli accessi anonimi. E’ utile per rilevare i tempi di attività e nel caso in futuro vengano abilitate funzioni per anonimi da trasformare poi in utenti (nello stile Shopping cart, per intenderci)

AVVERTENZE: Autenticazione NET, Applicativa, Ruoli, policies e Permessi non hanno nulla a che vedere con le regole dei gruppi/profili già esistenti di CitypostWeb4, che continuano a funzionare allo stesso modo di prima.

Struttura fisica del sito Le pagine sulla root sono comuni a tutta la WebApp, e corrispondono agli entry point, richiamabili da url classici. Site.Master Default.aspx, Contact.aspx, About.aspx corrispondono alla home e le pagine informative classiche della vetrina iniziale del sito da autente Anonimo Site.Master è la master page, e contiene le regioni comuni a tutte le pagine.

Page 9: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Ogni pagina aspx, eccetto ajax.aspx, ha come Masterpage questa o un’altra MasterPage che a sua volta punta a questa E’ divisa in 5 sezioni variabili a seconda del contenuto delle pagine. Su HeadContent viene fatto il rendering html dell’header , script, css, metatag e contenuti che vanno dal tag <head> al tag </head> FeaturedContent contiene i pulsanti e/o menu specifici di ogni singola pagina aspx a seconda delle caratteristiche che deve svolgere. Toolbar viene utilizzato per i pulsanti specifici di una griglia MainContent viene utilizzato per il rendering di griglie di dati, <table>, contenuti dinamici. Sostanzialmente corrisponde al tag <body> della pagina. MenuSinistro viene utilizzato per i menu specifici per una sotto-webapp NavBar e Footer sono impostati in modo statico sulla Home e restano invariati per il periodo che dura la sessione L’accounting è demandato alle pagine contenute nella sottocartella \Account. Ogni avvio di sessione viene eseguito il login e reindirizzato sulla home se l’account è in cache ed è valido, altrimenti si ferma sulla pagina Login.aspx.

Fig 2. Regioni di rendering html del sito

Struttura Logica

Page 10: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Per questioni di praticità, compatteza del codice, e performance reali dei tempi di risposta delle richieste, sono state adottate le seguenti 3 strategie di sviluppo

1) Tutto il layout di stile e grafico è controllato da regole CSS in bootstrap.css 2) Tutte le funzionalità client sono controllate da funzioni jQuery standard e Javascript

personalizzato nel file \Script\citypost.js 3) Tutte le chiamate al server che richiederebbero il refresh della pagina sono chiamate

Ajax e sono totalmente contenute nel file ajax.cs

bootstrap.css E’ il raccoglitore di regole css piu evoluto e usato nel 2015 per i siti web attualmente in rete. WordPress, Google, Microsoft, Twitter, sono solo alcuni tra gli utilizzatori. Fornisce caratteristiche Responsive affidabili e di alta precisione. I temi Responsive sono i siti web scalabili a seconda delle dimensioni dello schermo, che sia Desktop, telefono o Tablet. Bootstrap espone una svariata gamma di utilities gia confezionate e pronte all’uso che integrate con jQuery potenziano e facilitano lo sviluppo di apps di portali web moderni e dispositivi mobile. jQuery La MasterPage Site.Master istanzia nell’header, carica e poi inizializza citypost.js alla fine del rendering sul browser. Ovvero, nel dettaglio: - Nell’header include citypost.js - Esegue il rendering della pagina *.aspx (una qualsiasi) nei rispettivi ContentPlaceHolder

creando tutti i tag html - Inizializza la variabile master e rende visibile jQuery al nostro file js

<script type="text/javascript"> JavaScript: try { master.init({ jquery: jQuery }); } catch (err) { ShowErrorMessage(err); }; </script>

- Solo a questo punto (a fine rendering) tutti i tag contenuti nella pagina del browser sono visibili a jquery e al nostro citypost.js

Ajax Base tecnologica: è il sistema per evitare il postbak e refresh dell’intera pagina quando si vuole aggiornare solo una sua porzione. Il principio è semplice: la chiamata al server è fatta dal client in Javacript a cui viene detto il tag <div> in cui scrivere il Response.Write da C#

Page 11: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Ajax è il core back-end di questa web application. Concettualmente il sito è strutturata seguendo questa semplice regola: “Apri la pagina una sola volta caricando dal server tutto il possibile che ti serve, poi tutto quello che manca dopo lo chiedi ad Ajax dal client “ E’ esattamente ciò che avviene. In questo modo avremo un singolo Page_Load lato C# in cui aprire le connessioni, definire i datacontext, caricare Listbox statici, definire pulsanti ecc. Tutto cioè che deve arrivare dal server come prima istanza della pagina si fa nel Page_Load. Successivamente, se al click su un ListBoxItem, deve essere visualizzata una griglia di dati, si esegue all’Onclick javascript: cpAjax('<div>’, 'url’) Dove <div> è l’id del contenitore che riceve l’output, url la la chiamata alla pagina ajax “/ajax?action=test&ecc ecc” Il codice c# in ajax.cs farà il parser della querystring in entrata e nel Response.Write scriverà tutto l’html che serve per la corretta visualizzazione dei dati sulla pagina

Un esempio pratico: sulla pagina abbiamo un tag div con id pippo che non contiene nulla <div id="pippo"></div>

Da javascript si chiama cpAjax('pippo’, 'http://192.168.16.200:4560/ajax?action=test’) nel file Ajax.cs, dopo aver valutato la QueryString action = test, se avessimo questa istruzione var action = Request.QueryString["action"]; if (action != null && action == "test")

Response.Write("prova");

all’uscita della call troviamo sulla pagina del browser <div id="pippo">prova</div>

Questo permette di accedere al server ogni volta che serve senza dover aggiornare tutto il resto della pagina e intrigarsi con i PostBack e Reloads.

Sicurezza Ajax Per evitare che dal browser possa essere inserito manualmente un link operativo, ad esempio di cancellazione record, è stato previsto un passaggio di chiavi che lega la pagina chiamante al server che esegue l’operazione. Ogni volta che arriva la pagina sul browser viene generato una GUID diversa dal suo componente C#. Il client invia questo codice dal browser al server ed Ajax continua solo se ha trovato corrispondenza. Le chiamate ajax sono attive solo su pagine che hanno eseguito l’autenticazione, quindi dall’esterno o manualmente non è possibile fargli eseguire qualcosa, va in errore.

Esempio pratico Creazione di una nuova pagina con ASP.Net 4.5, jQuery, BootStrap, Ajax, LinQ to SQL

Page 12: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Aggiungi un nuovo elemento Web Form ASP.NET di nome test.aspx e seleziona Site.Master come MasterPage Il corpo della pagina appena creato si presenta come segue <asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" Runat="Server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="FeaturedContent" Runat="Server"> </asp:Content> <asp:Content ID="Content3" ContentPlaceHolderID="ToolBar" Runat="Server">

.. metti qui il DropDownList .. </asp:Content> <asp:Content ID="Content4" ContentPlaceHolderID="MainContent" Runat="Server">

.. metti qui il tag Div vuoto .. </asp:Content>

Aggiungi un ComboBox (DropDownList) nell’area FeaturedContent o ToolBar

<asp:DropDownList ID="cbUsers" runat="server" Width="234px" ClientIDMode="Static"> <asp:ListItem>Utenti</asp:ListItem> <asp:ListItem>Ruoli</asp:ListItem> <asp:ListItem>Profili</asp:ListItem> <asp:ListItem>Applicazioni</asp:ListItem> </asp:DropDownList>

E nel MainContent

<div id="listTable"> <%-- qui ci va il response ajax --%> </div>

inserisci nel Page_Load del *.cs

cbUsers.Attributes.Add("onchange", "SelectSecurity(this);");

Crea la function SelectSecurity(this) in citypost.js

function SelectSecurity(item) { if (item.value=='Utenti') { cpAjax('listTable', CreateAjaxCall('ADMIN', 'GetUsers')); } }

cpAjax e CreateAjaxCall sono gia fatte, basta richiamarle e fanno tutto da sole Scrivi il codice dentro il file ajax.aspx.cs che dovrà renderizzare sul tag listTable per action=GetUsers

Page 13: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

if (a == "GetUsers") { Response.Write("<select class=\"form-control\">"); AspNetDataContext db = new AspNetDataContext(); var ds = db.Users; foreach (var r in ds) { Response.Write("<option value =\""+ r.UserId.ToString()+"\">"+ r.UserName + "</option>"); } Response.Write("</select>"); }

Sequenza eventi - Pipeline

Per impostare i breakpoint in fase di sviluppo è importante sapere cosa succede quando un client accede al sito, quando e cosa fa una parte di codice:

seq File Evento Cosa fa 1 Global.asax Application_Start Viene inizializzata la variabile di

Sessione pubblica, avviato il Logger, registrati gli scripts MS e Accessi esterni

2 “” Session_Start Controllo autenticazione. Attenzione che se l’utente è memorizzato nella cache, qui è gia stato caricato in Context.User, fa tutto aspnet

3 Site.Master.cs Page_Init Check cookies, anti xfr, genera tokens di sicurezza

4 “” Master_Page_Preload Anti-xfr 5 Default.cs Page_Load Per ora nulla 6 Site.Master.cs Page_Load Inizializza le impostazioni di

paginazione

Attenzione che Application, Session e Page hanno Lifecycle differenti. Le classi statiche pubbliche ad esempio sono vive dalla Application_Start alla Application_End

Suddivisione aree applicative e separazione contesti Come è noto, i servizi Citypost e SailNet hanno utenze e contesti completamente diversi. La caratteristica che condividono è l’assistenza. Questo portale ha lo scopo di unificare le attività per i Redattori e Admin, e separarle per l’utente finale, che sia uno stampatore, una agenzia o PPA. Come si ‘dovrebbe’ poter intuire dallo schema sottostante, all’apertura del sito viene richiesta la pagina di Default.aspx sulla root. A seguito di un flusso di controlli che vengono fatti in fase di autenticazione si viene rediretti sulla webApp di pertinenza.

Page 14: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Messaggistica (programmazione) In aggiunta alla modalità standard di Logging dei messaggi di LibComuni, è stato adottato un metodo per la gestione dei messaggi in modo tale che durante la programmazione possano essere inviati al browser in 3 modi differenti a seconda dei contesti server o client, senza che sia necessario nessun refresh della pagina. Su site.master sono stati inseriti 3 tag div nascosti di colore diverso

Page 15: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Questi 3 elementi, quando viene cariata la pagina, sono nascosti di default. La function sul client (in citypost.js) che li rende visibili è la SendMessage. Da qualsiasi parte del sito in cui ci sia la necessità di informare l’utente attraverso un messaggio, la chiamata viene fatta a questa function sul client. Se stiamo programmando sul contesto client è piuttosto semplice perche la chiamata è diretta. Dal server in C# possiamo trovarci in due contesti diversi:

- nel PostBack di una qualsiasi pagina aspx (es Page_Load) - nel rendering di codice html all’interno di una chiamata asincrona AJAX

Nel primo caso basta aggiungere uno o piu messaggi alla coda attraverso il metodo predisposto string Message = "\"Credenziali applicative non valide. Contattare l'assistenza\""; WebHelper.AddMessageQueue("Avviso autenticazione!", Message, 2);

site.master, alla fine del caricamento della pagina lancerà lo script SendMessage contenente la coda (vedi in fondo alla pagina site.master) <% WebHelper.cpHtml.renderServerMessage(Response); %> Nel secondo caso, non essendo in corso un ‘Loading’ della pagina, il SendMessage viene eseguito al completamento della funzione Ajax richiesta, ed è suffciente informare il metodo renderServerMessage true che la chiamata è asincrona: WebHelper.AddMessageQueue("Errore sicurezza", "La chiamata ajax non superato la convalida di sicurezza", 1); WebHelper.cpHtml.renderServerMessage(Response, true);

Da C# i messaggi possono essere inviati alla coda in qualsiasi momento e in numero illimitato. La prima volta che viene ricaricata Site.Master saranno visualizzati ed eliminati dalla coda.

CheckList Manutenzione sito Cose da fare e tenere presente quando si crea una nuova pagina o si aggiunge una caratteristica

Come da prassi è consigliabile individuare la pagina piu simile a quella che deve essere implementata e farne una copia. Ad ogni modo qualsiasi sia la strategia scelta per aggiungere cose è importante che ciascun sviluppatore adotti gli stessi strumenti adottati per il resto del sito.

Page 16: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

MasterPage: Nessuna pagina deve essere senza Master Page, a meno che non lo richieda la caratteristica specifica. Senza MasterPage vengono saltati alcuni controlli di sicurezza e non ci sono script clients collegati, né funzionalità ajax. Anche una semplice pagina informativa deve passare dal Core del sito. I sottositi SailNet e CityPost hanno la loro Master Page. Tutte le pagine aspx City devono avere AppMaster.Master, tutte le Pagine Sail devono avere come SailnetPage.master

Scripts Bootstrap.css, js, less e tutti i js jQuery non devono MAI essere modificati, in quanto sono OpenSource e sicuramente verranno aggiornati. Utilizzare files css o js propri per aggiungere metodi o fare l’override su metodi esistenti

Web.Sitemap ogni nuova pagina creata deve essere aggiunta a questo file. Non tanto per la funzionalità del sitemap ma per la visualizzazione del breadcrumb. Ogni voce inserita in questo file verrà mostrata sull’header delle pagine

Web.config: L’unica ConnectionString che viene letta dal file di configurazione è

DefaultConnection e deve rimanere sul file perche a lei si riferisce tutto il motore di autenticazione asp.net. Le altre connectionstring presenti sono per sviluppo su db locale. In produzione o in azienda vengono lette da LibNormalizza

<appSettings> <!--localhost usa tutte le connectionstring da qui, LibNormalizza le prende dalle impostazioni della libreria--> <!--<add key="SQLServer" value="localhost"/>-->

<add key="SQLServer" value="LibNormalizza"/> <!--<add key="SQL-LocalServer" value="FABIO-PC"/>--> <!--<add key="SQL-LocalServer" value="NBKFABIO8G\SQLEXPRESS"/>-->

Su SQLServer ci va il nome di sqlserver locale, nel caso in cui SQLServer sia impostato su localhost

Modifica db di Autenticazione ASP.NET Nel caso si renda necessario ripartire da zero su un nuovo server o spostare le tabelle asp net di autenticazione, modificare la DefaultConnection Poi avviare l’applicazione, se non viene trovato l’utente admin lo crea da solo, cosi come i ruoli di base minimi per l’avvio e la manutenzione amministrativa. Se l’utente viene creato dal sito, utente e password sono admin e $.0iìçfe025G

Messa in produzione Ipotesi di passaggio in produzione

Per l’hosting rimando a delle letture fatte in questi giorni che, con una visione a largo raggio potrebbero essere prese in considerazione dal settore marketing. Il Cloud Azure di Microsoft fa offerte di hosting a partire da 20 euro al mese, mi sembra 250GB!!. Una volta pubblicato il sito può essere utilizzato sia dal personale interno che dagli utenti esterni. Per le utenze Citypost potrebbero essere importate tutte le credenziali esistenti in un colpo solo,

Page 17: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

creata una password fittizia che al momento dell’accesso l’utente puo cambiare. Gli abbinamenti ID/PWD applicative resterebbero comunque legati al db esistente. Per le utenze SailNet potrebbero essere importate tutte le agenzie attive e abbinate allo stesso modo di citypost, le credenziali Poiché è possibile autenticarsi con Google o ID Microsoft, Facebook o Twitter, è da valutare l’effettivo porting massivo delle utenze. I benefici di una autenticazione con account Social è che integrano la pubblicazione di notizie automatiche e che, considerando che una buona parte degli utenti già utilizza dispositivi mobili (il sito è perfettamente compatibile) sarebbe consigliabile spingere gli utenti a questo tipo di autenticazione.

Page 18: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Business Layer Modificata il ven, 08 mag 2015 10:31

Categorizzata come: Backend

1. Riferimenti

1.1 Abbreviazioni

Nel seguito valgono le seguenti abbreviazioni: SI: Sistema informativo PL: Presentation Layer BL: Business Layer DAL: Data Access Layer ORM: Object Relational Mapping DTO: Data Transfer Object LINQ: Language-Integrated Query EF: Entity Framework MVC: Model View Controller

2. Processo

Si tratta di separare in strati logici (Layers) il sistema informativo intero. La tipica suddivisione prevede tre strati logici diversi:

o Accesso ai dati (DAL): è lo strato che si occupa della lettura/scrittura dati (persistenza) tipicamente su un database.

o Logica di business (BL): è lo strato oggetto di questo lavoro. Racchiude tutta la logica applicativa del SI e fornisce oggetti e metodi controllati per implementare questa logica.

o Strato di presentazione (PL): è la parte dell'interfaccia rivolta all'utente finale. Può essere una apllicazione web, windows form e anche console.

Page 19: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

I pricipali vantaggi di questa architetura sono:

o Le modifiche implementative/migliorie di ogni strato non impattano sugli altri strati purché venga rispettata l'interfaccia di comunicazione tra gli strati stessi

o Possibilità di mettere dei team di lavoro diversi su ogni strato in contemporanea

o Di solito si ottengono applicazioni client più leggere e modificabili

3. Implementazione

DAL La prima cosa realizzata è un repository dei modelli dati. Cioè un unico posto in cui siano definiti gli oggetti del "mondo" del nostro SI. Alcuni esempi sono l'oggetto Utente del SI, l'oggetto Soggetto che può essere un cliente piuttosto che un'agenzia. Questi oggetti sono tutti definiti nel progetto Citypost.Common il cui nome parla molto più di ogni spiegazione. I metodi che lavorano su questi oggetti sono il BL (Citypost.BL). Può essere necessario definirsi una struttura dati anche lato client, ma si tratta di strutture ausiliari e non principali. Ad ora sono stati formalizzati soltanto gli oggetti Utente, Cliente e alcuni oggetti di servizio (tipicamente legati alle tabelle di decodifica del db). La parte di lavoro (consistente) da fare ancora è quella di formalizzare tutti gli altri oggetti necessari ad implementare le logiche che man mano verranno richieste. Le classi per formalizzare gli oggetti devono essere solo contenitori con properties get/set. Cioè sono semplici DTO e non oggetti complessi come Datatables,DataSets o peggio interi oggetti di business. Infatti devono essere il più leggeri possibile visto che sono responsabili del trasporto dati. Gli strumenti accettati nel nostro BL per questa attività sono: LINQ, EF oppure DTO fatti "a mano". È fuori tema discutere qui quali di questi ORM sia il migliore, se c'è. Per chi è interessato, qui trovate un confronto tra i DTO fatti con puro ADO.NET e EF ADO.NET VS EF Performance Certo è che vale la massima "chi fa per sé...." poiché gli ORM

Page 20: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

ufficiali aggiungono normalmente un po di cose loro e impogono che a ogni modifica venga rigenerata la classe. È per questo che sia LINQ che EF non hanno bisogno di particolari meccanismi per gestire la persistenza (ce l'hanno on board) e invece i DTO fatti a mano hanno bisogno di un oggetto Persister per salvare e leggere dal db. Il nostro Accesso ai dati sarà dunque DAL = Citypost.Common per i dati + LibDb per ADO.NET via driver nativo Sql Server o OleDb + LINQ/EF. Anche i file dbml di LINQ dovranno risiedere in Citypost.Common. BL Se chiamiamo OBJ un oggetto qualsiasi (DTO, classe LINQ e EF) lo si espone come OBJ, List<OBJ>, DataPage<OBJ> dove la DataPage è una struttura appositamente pensata per le applicazioni web. Naturalmente ci deve essere la possibilità di esporre dati semplici come un intero o una stringa. public class DataPage<T> { public List<T> Data = new List<T>(); public int RecordCount = 0; public int PageSize = 20; public int PageIndex = 0; public int PageCount { get{ return (RecordCount ==0 || PageSize==0) ? 0 : (RecordCount + PageSize - 1) / PageSize;}} }

Page 21: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Il BL visto da Visual Studio:

Il BL eroga servizi per ogni OBJ. Dietro le quinte vengono usate le classi sotto Persistance e Rules, ma le classi di interesse per l'utente del BL sono le classi sotto Services. Infatti le classi di supporto servono "soltanto" a gestire il tutto in modo object oriented. Gli oggetti del mondo del SI sono solo le classi sotto Services. Generalmente ogni cartella contiene la classe d'interfaccia che bisogna rispettare per creare un oggetto di un certo tipo. IDataMapper: è l'interfaccia che deve rispettare una classe Mapper. Se non si fornisce una specifica classe mapper viene usata la GenericMapper. Le classi generate con LINQ/EF NON hanno bisogno della classe mapper in quanto hanno tutto on board. interface IDataMapper { // Main method that populates dto with data Object GetData(IDataReader reader, string subClass = "" ); // Gets the num results returned. Needed for data paging. int GetRecordCount(IDataReader reader); }

Page 22: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

IModelDbDao: è la classe che definisce in quale formato devono essere restituiti i dati per l'accesso via ADO.NET. Le due classi che le implementano sono la classe di accesso che lavora con il driver Sql Server nativo (LibSqlDao) e quella che accede via OleDb (LibOleDbDao). Le classi che definiscono la Business logic (Services) sono quelle che andranno implementate per ogni OBJ complesso.

Tutte hanno a comune la classe ServiceBase che contiene oggetti e servizi di utilità per tutte le classi derivate:

public abstract class ServiceBase : IDisposable { private static bool _InitDone = false; // SharedSqlDao private LibSqlDao _sharedCPSIDao = null; private LibSqlDao _sharedDBLOGDao = null; private LibSqlDao _sharedGAPDao = null; private LibSqlDao _sharedLOGINDBDao = null; private LibSqlDao _sharedNORMARCDATIDao = null; private LibSqlDao _sharedSAILREPORTDao = null; private LibSqlDao _sharedSRVCTARCDATIDao = null; Dictionary<DataSourcesNames, DataSourcesDTO> AllDataSources;

Page 23: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

private static List<Applicazione> _allApps = null; public List<Applicazione> AllApps { get { if (_allApps == null) { string query = @"SELECT * FROM [dbo].[TbSecApplications]"; IDbCommand command = _sharedCPSIDao.CreateCommand(query); _allApps = _sharedCPSIDao.GetEnumerable<Applicazione>(command).ToList(); } return _allApps; } }

Da notare l'uso del paradigma Singleton per la lista delle applicazioni. Questo permette di ottenere un caricamento dei dati "on demand" soltanto la prima volta che servono. In effetti è assolutamente improbabile che la lista delle applicazioni del SI cambi durante la vita di una singola istanza del BL. Si possono notare all'inizio della classe le variabili che definiscono tutte le fonti dati potenzialmente accedute dal BL. Questa lista sarà soggetta a notevoli modifiche... La scelta per l'accesso ADO.NET è quella del driver nativo di Sql Server La classe DynamicLibrary serve a gestire le query dinamiche di LINQ ed è l'unica che non fornisce direttamente dei servizi. Il linguaggio utilizzato per esprimere la logica di business è semplicemente sql per gli oggetti gestiti da ADO.NET e le query LINQ per gli oggetti definiti nei file .dbml. Esempio di metodo con sql public UtenteDTO DoLogin(string userName, string passWord) { string query = @"SELECT u.*, d.IdPRA FROM [dbo].[TbSecUtenti] u inner join [dbo].[TbSecProfiliPerRuoliApp] d on u.GuidUtente = d.GuidUtente and d.AppAttiva = 1 and d.ProfiloAttivo = 1 WHERE u.UsrName = @UsrName and u.Pswd = @Pswd"; LibSqlDao dao = SharedSqlDao; IDbCommand command = dao.CreateCommand(query); dao.AddParameter(command, "@UsrName", userName); dao.AddParameter(command, "@Pswd", passWord); return dao.GetSingle<UtenteDTO>(command); }

Esempio di metodo con LINQ public List<Buste> GetBusteByCap(string cap, int quante, BusteSortOption order) { string where = "Cap == " + Quota(cap).Replace('\'', '"'); string ordby = GetOrderBy(order); return BustePersister.Bustes.Where (where) .Take(quante) .OrderBy(ordby).ToList(); }

N.B. gli esempi non corrispondono all'attuale implementazione.

4.2 Test

Page 24: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Per i test ho utilizzato un programma di console (TestBLConsole) per le operazioni più banali. Per i test riguardanti la paginazione dei dati, l'ordinamento ecc... è stato utilizzato una web app fatta con ASP.NET MVC V4 (TestBLMVC). La scelta del framework MVC è stata dettata da alcune considerazioni:

o Questo lavoro, dopo vari studi, si basa su un lavoro reale testato appunto con una web app MVC

o La "separation of concern" del pattern MVC, fa si che la parte Model sia esattamente il BL

o L'architettura MVC consente di ottenere un'ottima scalabilità e si presta bene a l'aggiunta di funzionalità da testare per complesse che siano

o La parte di presentation (View) può essere gestita da personale dedicato al markup poiché contiene solo html e script di tipo razor/aspx

Riferimenti:

ASP.NET MVC Overview Difference betweeen ASP.NET WebForms and ASP.NET MVC Comparing Web Forms And ASP.NET MVC

4.4 Database

CPSI su Pomezia DBLOG su DbServer GAP su FILESERVER2 LOGINDB su DbServer ARCDATI su NORMBATCH SAILREPORT su SRV_CITY1 ARCDATI su SRV_CITY1

4.5 Link progetti o sottoprogetti

o Installazione Business Layer in ambiente Visual Studio o Sito PostSharp

Page 25: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Il Front End

Redatto da Fabio Guerrazzi – 3/01/2016 In questo capitolo descrivo nel dettaglio le caratteristiche del FrontEnd Componenti e plugin utilizzati (INSPINIA Admin Theme – acquistato per 18$)

Componente Descrizione Riferimenti Versione

Visual Studio 2012 IDE di sviluppo C# ASPNet

Vedi dettaglio esteso sotto Update 5

font-awesome Icone del sito (circa 250)

4.5.0 update da 4.3.0 il 3/1/2016

Animate.css Contiene classi animazioni CSS3

http://daneden.me/animate 3.5.0 (2016)

Bootstrap Framework per layout pagine

http://getbootstrap.com/ v3.3.6 (2016)

DevOOps Plugin kit admin http://devoops.me 2.0

INSPINIA Plugin kit admin http://webapplayers.com/inspinia_admin-v2.4

v2.4 (2016)

Bootbox.min.js Alert, prompt, popup

http://bootboxjs.com 4.4.0 (2016)

Bootstrap-datepicker-master

Innovative datepicker

https://github.com/eternicode/bootstrap-datepicker

1.6.0 (2016)

tw-sack.js Simple AJAX Code-Kit (SACK) v1.6.1

https://code.google.com/p/tw-sack

1.6.1 (stable dal 2008)

autoNumeric.js Check input numerici

http://www.decorplanit.com/plugin/ 1.9.3.3 (2015 stable)

js.cookies.js Handle cookie via jquery

https://github.com/js-cookie/js-cookie 2.0.1 (2015) stable

Jquery.validate.js Jquery validazione http://jqueryvalidation.org/ 1.14 (2015)

Page 26: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

DevOOps plugin Twitter Bootstrap http://getbootstrap.com 3.2.0 Bootstrap Validator https://github.com/nghuuphuoc/bootstrapvalidator 0.5.2-dev MIT D3 http://d3js.org/ 3.4.11 AS IS Datatables http://datatables.net 1.10.3-dev GPL or BSD Fancybox http://fancyapps.com/fancybox/ 2.1.5 ? Widen FineUploader https://github.com/Widen/fine-uploader (GPL3) v 5.0.5 jQuery-Knob http://anthonyterrien.com/knob/ (MIT or GPL) 1.2.11 Flot www.flotcharts.org 0.8.3 AS IS Select2 https://github.com/ivaynberg/select2 3.5.1 GPL2 Fullcalendar http://arshaw.com/fullcalendar 2.1.1 MIT jQuery 2.1.1 http://jquery.com jQuery-UI 1.11.1 jQuery Timepicker http://trentrichardson.com/examples/timepicker/ 1.5.0 MIT Justified Gallery https://github.com/miromannino/Justified-Gallery 3.2.0 Creative Commons 3.0 Moment http://momentjs.com/ 2.8.3 MIT Morris Charts http://morrisjs.github.io/morris.js/ v0.5.1 MIT RaphaelJS http://raphaeljs.com/ 2.1.2 MIT jQuery Sparkline http://omnipotent.net/jquery.sparkline/ 2.1.2 BSD TinyMCE http://www.tinymce.com 4.1.5 GPL2 xCharts http://tenxer.github.io/xcharts/ 0.3.0 AS IS Springy http://getspringy.com/ 2.6.1 AS IS Chartist.js http://gionkunz.github.io/chartist-js/index.html 0.1.15 AS IS OpenStreetMap http://openlayers.org 2.13 BSD Leaflet.js http://leafletjs.com 0.7.3 AS IS

Dettaglio ottenuto della finestra About di un Visual Studio 2012 tipo (2013/2015 sono comunque compatibili) Microsoft Visual Studio Ultimate 2012 Versione 11.0.61219.00 Update 5 Microsoft .NET Framework Versione 4.6.01038 Edizione installata: Ultimate Architecture and Modeling Tools 04940-004-0038003-02233 Microsoft Architecture and Modeling Tools UML® e Unified Modeling Language™ sono marchi o marchi registrati di Object Management Group, Inc. negli Stati Uniti e in altri paesi. Controllo ortografico analisi codice di Visual Studio 2012 04940-004-0038003-02233 Controllo ortografico analisi codice di Microsoft® Visual Studio® 2012 Parti di International CorrectSpell™ spelling correction system © 1993 by Lernout & Hauspie Speech Products N.V. Tutti i diritti riservati. The American Heritage® Dictionary of the English Language, Third Edition Copyright © 1992 Houghton Mifflin Company. Versione elettronica concessa in licenza da Lernout & Hauspie Speech Products N.V. Tutti i diritti riservati. LightSwitch per Visual Studio 2012 04940-004-0038003-02233 Microsoft LightSwitch per Visual Studio 2012 Strumenti di sviluppo di Office 04940-004-0038003-02233 Strumenti di sviluppo di Microsoft Office Strumenti di sviluppo di SharePoint in Microsoft Visual Studio 2012 04940-004-0038003-02233 Strumenti di sviluppo di SharePoint in Microsoft Visual Studio 2012 Team Explorer per Visual Studio 2012 04940-004-0038003-02233 Microsoft Team Explorer per Visual Studio 2012 Visual Basic 2012 04940-004-0038003-02233 Microsoft Visual Basic 2012

Page 27: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Visual C# 2012 04940-004-0038003-02233 Microsoft Visual C# 2012 Visual C++ 2012 04940-004-0038003-02233 Microsoft Visual C++ 2012 Visual F# 2012 04940-004-0038003-02233 Microsoft Visual F# 2012 ASP.NET and Web Tools 2012.3.41009 Microsoft Web Developer Tools contains the following components: Support for creating and opening ASP.NET web projects Browser Link: A communication channel between Visual Studio and browsers Editor extensions for HTML, CSS, and JavaScript Page Inspector: Inspection tool for ASP.NET web projects Scaffolding: A framework for building and running code generators Server Explorer extensions for Windows Azure Web Sites Web publishing: Extensions for publishing ASP.NET web projects to hosting providers, on-premises servers, or Windows Azure Gestione pacchetti NuGet 2.6.40627.9000 Gestione pacchetti NuGet in Visual Studio. Per ulteriori informazioni su NuGet, visitare il sito Web http://docs.nuget.org/. JetBrains ReSharper 8.0.2 Full Edition build 8.0.2000.2660 on 2013-09-27T08:18:12 JetBrains ReSharper 8.0.2 package for Microsoft Visual Studio. For more information about ReSharper, visit http://www.jetbrains.com/resharper/. Copyright © 2003–2016 JetBrains, Inc. PostSharp 4.1.12.0 SQL Server Data Tools 11.1.20627.00 Microsoft SQL Server Data Tools Visualizzatore PreEmptive Analytics 1.0 Estensione di Microsoft Visual Studio per visualizzare i riepiloghi aggregati dal prodotto PreEmptive Analytics. Introduzione alla logica del sito Il sito fa uso massiccio di Ajax. in uno scenario tipico, il flusso di chiamate è il seguente a) click pulsante sulla pagina con onClick ad una funzione js che esegue cpAjax b) caApajx apre un thread asincrono sulla pagina ajax.aspx c) ajax.cs splitta l'url creando l'oggetto PatternUrl, che contiene tutte le informazioni validate e pronte al parsing d) ajax.cs quindi avvia AsyncHelper.ProcessAsyncRequest, in cui tutte le Action Key sono concentrate, per ognuna di esse esegue la funzione di validazione e rendering. Un utilizzo tipico è snStorage e) in snStorage viene generato il codice html e scritto sul Response.Write. f) snStorage rappresenta il layer di comunicazione e trasferimento dati tra server e client. in alcuni casi fa accesso diretto al DB,ne legge il contenuto e lo scrive sulla pagina. nella maggior parte dei casi usa BusinnessLogic.

Page 28: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

g) il BL è composto a Mapper e oggetti - il mapper ha lo scopo di aprire le connessioni, preparare gli oggetti, paginazione, filtri, ordinamento specifico per le query successive - viene istanziato il mapper specifico - Viene richiamato il metodo di restituzione oggetti fisici h) snStorage vede solo mapper e oggetto restituito. Non apre coonessioni con il db. LibNormalizza, LibArchiviaMpx, LibDati, sono tutti referenziati nel mapper. nè l'oggetto entity, nè l'intero sito deve avere referenziati librerie, linq, query sql di accesso ai dati. i) snStorage usa TemplateHeler per il rendering e il layout dei dati. i templates sono semplici files html contenenti tag statici e variabili passate da snStorage i campi variabili aprendo un file template sono tutti i valori racchiusi tra %% stack di chiamate pseudo code 1 [ Button_click ] funzione click nel js della pagina funzione cpAjax(<action key>) in citypost.js (<--qui stacca il thread) apre ajax.aspx parse della querystring su PatternUrl parse della <action key> in ProcessAsyncRequest individua l'action key SailWeb.snStorage.renderXXXX(<action key>) apre il mapper, inizializza i dati e corpo di paginazione carica il buffer di dati richiesti SailWeb.TemplateHelper HEADER, scrive l'header della griglia scorre i records SailWeb.TemplateHelper ROW, scrive la riga della griglia end loop SailWeb.TemplateHelper FOOTER, scrive i totali e footer della griglia stack di chiamate pseudo code 2 [ Button_click ] citypost.js -> cpAjax(<action key>) open ajax.aspx ajax.cs .. <- getPatternUrl() AsyncHelper.cs-> ProcessAsyncRequest(<action key>) .. switch case action key SailWeb.snStorage.renderXXXXXXX(param) open mapper

Page 29: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

read and get buffered page records .. SailWeb.TemplateHelper(<template file>) while buffer end-> response.write(record) è uguale dappertutto Concetti CLIENT - Il core jQuery lato client si trova nel file citypost.js - usa la pagina ajax.aspx per passare la richiesta al server - l'url e i parametri viene costruito in citypost.js dalla funzioen caAjax cpAjax accetta 2 parametri 1- string, id del div contenitore su cui viene scritto il Response.Write("..") dal server 2- url della pagina con tutti i parametri necessari alla funzione specifica cpAjax(uno, due); il parametro due viene costruito dinamicamente dalla funzione CreateAjaxCall(SystemArea, Action) CreateAjaxCall accetta due parametri 1 - key string del contesto. Non è utilizzato, ma puo essere utile per sapere se la chiamata arriva da System, Royalities, Competenze, Anagrafiche ecc 2 - string key Action contiene tutti gli elementi per informare il server all'esecuzione di una specifica funzione e tutti i suoi parametri CreateAjaxCall per prima cosa recupara la root del sito , poi ci aggiunge la pagina /ajax.aspx piu tutti i parametri della query. var p = GetBaseSitePath(); p += "/ajax.aspx?System=" + SystemArea + "&Action=" + Action + "&page=1&filtro=&orderby=&rows=" + rows + "&CSV=" ; Action contiene stringhe separate dal carattere ;

Page 30: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Il primo elemento è la action vera e propria, tutto il resto sono parametri. Componenti della querystring &Action = <string key + parametri> &page=<pagina corrente> &filtro= <string filtro da applicare alla tabella di pertinenza> $orderby= <nome del campo sul db su cui ordinare> &rows= <numero di righe visuallizzabili sulla griglia> &CSV=1 <se valorizzato a 1, riesegue il get dei dati della griglia ma si scrive su csv e non a video) &ApiKey <GUID univoco generato al loading della master.page. il server sa sempre che la chiamata è stata fatta da funzioni applicative. in questo modo impedisce l'esecuziona ajax direttamente da url> Falgs e diverse modalita operative una chiamata ajax essendo di per se asincrona, avvia un thread separato e restituisce immediatamente il controllo al brwoser. qui per default viene visualizzato un div a schermo intero semitrasparente con uno spinning java animato che impedisce di far compiere altre azioni agli utenti web fino a quando tutto il response non è stato generato e la call ajax completata non tutte le chiamate devono essere cosi. si puo fare una richiesta in background, e fare cose diverse al suo completamento a seconda dell'action passata. per pilotare tutte queste condizioni uso delle variabili AjaxNoWait= true non blocca il browser AjaxCompletedExecCode = x ; un codice numerico che fa eseguire una specifica funzione al completamento della richiesta aax AjaxRefresh = true; fa il reload della pagina al completamento della chiamata uso il sistema seguente se cambia qualcosa a video (edit, cancellazone di un elemento di una grid), e aggiorna il contenuto esattamente com'era AjaxCompletedExecCode = 1; AjaxBackupCall(); <-- salva url e div cpAjax(preDiv, CreateAjaxCall('SYS', 'unlockuser;' + user)) <- nuova chiamata AjaxLastCall(); <- richama url e div salvato ..in questo caso sblocca un utente e cambia l'icona del pulsante

Page 31: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

WEB SERVICE WS.ASHX L'unica ragione per cui esiste un web service in questo sito è perche era l'unico modo per visualizzare la progressbar. poiché deve essere asincrono esattamente come ajax e ajax non puo avere 2 istanze contemporanee (le puo avere ma il pilota sembrerebbe ubriaco, ovvero è un casino), il ws consente di avere thread asincroni paralleli senza che bisticcino ciò non toglie che un domani, se si rende necessario un get/set di passaggio json da e verso l'esterno, l'elemento esiste e si puo implementare. al momento non serve , come gia detto, il WS gestisce solo la PB PROGRESSBAR nella funzione js che si vuole una PB durante l'elaborazione ajax, basta aggiungere function ShowUsers() { StartProgress("Elenco Utenti"); <----------- usa questo per inizializzare la progress bar cpAjax('listTable', CreateAjaxCall('ADMIN', 'persone;full')); <-- chiama ajax } in c# dove elabori PERSONE incrementa WHelper.Percentage = x; e ogni mezzo secondo viene letto il valore e messo sulla progressbar. fa tutto da solo, chiude e nasconde i tag cpAjax quando ha finito questo polling ogni 0.5s viene fatta una chiamata WS, in quanto il sistema ha gia in pancia una chiamata asincrona ajax, non ne puo fare due contemroranemanete. il servizio puo girare in parallelo, è ancora un altro thread purtroppo non si puo fare in POST su un form asp.net. se fai click su un button runat="server" dovresti prima ricaricare la pagina, avviare l'attesa, la progressbar. nze po fa ho provato e toccherebbe fa dei giri IsPostBack, QueryString, esecuzione di script client, che lo rendono ingestibile

Page 32: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

Concetti applicati a lato SERVER ajax.cs supponendo che come action gli viene passato "DECODAGE;10030" 1) verifica subito se l'apikey corrisponde a quella generata sulla master.page 2) crea il pattern interpretando la querystring 3) esegue AsyncHelper.ProcessAsyncRequest(Context, Pattern); AsyncHelper.cs esegue 1) interpreta la action "DECODAGE", inzializza idAge 2) esegue SailWeb.snStorage.renderAgenzia(Response, idAge); renderAgenzia esegue 1) Istanzia il mapper di AnagraficaClienti 2) esegue AgeCurrentmyBL = anagMapper.GetByCodUnivoco(idAge); TemplateHelper.cs 1) esegue WriteDecodificaAgenzia(Response, "/Templates/agedecodifica.html", AgeCurrentmyBL); il template contiene tag html fissi e variabili %% sostituite dai valori di AgeBurrentmyBL ORDINE OGGETTI z-index (piu alto il numero, piu è vicino all'osservatore) aspetto DELICATO, sono un mare e con tanti oggetti che si sovrappongono sulla pagina è facile perdere il controllo z-index classe/id

pagina

descr. oggetto

0

il background (container, container-fluid, logo, breadcrumb..)

1000 (10) sidebar

Site.Master

pulsante del menu sinistro

1030 navbar-fixed

Site.Master

barra in alto arancione con user online, user logged, contatti ecc

Page 33: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

99999 preloader

Site.Master

rotellina animata di java, deve stare il piu alto in assoluto

1090 id="process-modal"

JobPopup.html

popup form "nuovo messaggio" (render in Messaggi.aspx)

1100 id="pdfModal"

PopupPDF.html

renderizzata dove richiesta (call via ajax in citypost.js)

1090 id="checkoutModal"

PopupTracer.html

renderizzata dove richiesta (call via ajax in citypost.js)

1090 id="checkoutModal"

PopupTracer_NOTFOUND.html renderizzata dove richiesta (call via ajax in citypost.js)

2001 modal

devoops.css

bootbox

1040 modal

bootstrap.css

(overrided da devoops.css)

1070 id="popModal"

popGapTracers.html

Popup elenco tracers sulle pagine competenze

100 ui-front

SmallParcel.aspx autocomplete jquery-ui

3000 !important (99) expanded

WinMove di devoops

draggable windows

1999 box

""

2001 (98) .main-menu .dropdown-menu

devoops i combo devono stare davanti alle window, le window dietro a ui-front = 100

MESSAGGI

Page 34: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

l'app ha 3 modalità funzionali per inviare messaggi alla pagina web. Client, Server http, ajax CLIENT in citypost.js c'è la SendMessage() che visualizza 3 tipi di messaggi con 3 colorazioni diverse: Info verde, Warning beige, Error in rosso. se stai sviluppando in js e vuoi informare l'utente basta la call a questa funzione. Se invece sei in C# sul server, devi sapere se stai processando un thread sincrono o asincrono, perche usano le stesse funzioni ma con parametri diversi. SERVER HTTP il principio è il seguente: tutti i messaggi e di qualsiasi natura vengono aggiunti a una coda messaggi del server e sparati a video da js. un ciclo di funzioni sparse per il sito può generare eccezioni e messaggi a volontà, vengono scritti a video dalla masterpage una volta sola alla fine del caricamento di ogni pagina aspx poichè dalla masterpage ci passa ad ogni cambio pagina, in fondo usa questa funzione <% SailWeb.cpHtml.renderServerMessage(Response); %> per leggere ogni elemento della coda e stamparlo nell'html come SendMessage java Esempio: AddMessageQueue("pippo è il cugino di topolino", 1); AddMessageQueue("ma sembra un po ricchione", 2); aggiunge i messaggio alla coda sul server, e quando passa dalla masterpage, nell'html ci scrive: .. <script> SendMessage('pippo è il cugino di topolino',1); SendMessage('ma sembra un po ricchione',2); </script> ..

Page 35: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

cosi il browser invia i due messaggi come se fossero parte della pagina html in corso. una volta scritti a video la coda viene cancellata, quindi sono importanti CurPage e DestPage *** SERVER AJAX *** le funzioni Ajax non hanno completamento di pagina, non c'è OnLoad e non c'è un termine di caricamento, quindi non può usare la SendMessage. <% WHelper.cpHtml.renderServerMessage(Response); %> scrive i tag veri e propri dentro il div in cui sta scrivendo html. **** CurPage e DestPage ***** per effetto di redirect o per altre mille ragioni, è possbile che il codice C# stia processando una determinata pagina ma i messaggi devono essere visualizzati su una differente. per assicurarsi che la coda messaggi non sia sparata e cancellata su una pagina di transito, va passato il parametro DestinationPage Ogni nuova pagina che si fa deve avere una tag che la identifica, come la default della root WHelper.CurPage = "DEFAULT"; e se vuoi che i messaggi siano scritti al rendering di una pagina specifica gli passi l'id (in questo caso "EXTDEF") WHelper.AddMessageQueue("Errore", ex, 2, "EXTDEF"); SE NON GLI PASSI NULLA FA IL RENDERING E SCARICA LA CODA SULLA PRIMA PAGINA CHE CARICA LA MASTER.. a video non si vede nulla GRIGLIE vengono tutte generate da ajax e SailPostGrid.js fa tutta l'impaginazione client da solo

Page 36: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

la chiamata ajax deve avere come elemento di contesto "GRID" cpAjax('listTable', CreateAjaxCall('GRID', 'persone;full')); perche funzioni deve: - il contenitore ajax DEVE avere la classe sw-grid <div id="cont-grid-ajax" class="sw-grid"></div> - la table DEVE avere la classe "sw-table-filtered" - deve essere definita almeno una colonna di intestazione con le indicazioni sul filtro esempio: <div id="ajax-container" class="sw-grid"> <table id="ft-usrs" class="sw-table-filtered table table-condensed table-bordered table-striped table-hover table-responsive no-border-bottom"> <thead> <th>*</th> <th>*</th> <th>*</th> <th>*</th> <th id="username-users" class="enable-filter" data-dbfield="UserName" data-type="string" data-table="users" Title="Ordina per Nome Utente" >UserName</th> </thead> </div> *** NOVITA' da metà settembre 2015 sono state introdotte griglie dinamiche. da una semplice o complessa select in puro T-SQL, il sito genera la grid con tutti i parametri per il filtro, ordinamento, paginazione, fa tutto da solo queste sono le 2 action della chiamata ajax, si trovano in AsyncHelper (io uso la 3, ma in alcuni contesti puo essere meglio la 2) case "QUERY3": SailWeb.LogIt(Context, "Richiesta parsing sql tipo 3 " + vars[1]); // nella query c'è server e catalog {server.catalog} SailWeb.snStorage.renderSQLRequest(Context, vars[1]); break; case "QUERY2": SailWeb.LogIt(Context, "Richiesta parsing sql di tipo 2 " + vars[1]); SailWeb.snStorage.renderSQLRequest(Context, vars[1],vars[2],vars[3]);

Page 37: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

break; nel parsing di tipo QUERY2 server e catalog sono 2 parametri, il terzo è la select. nel parsing di tipo QUERY3 server e catalog sono nella stringa sql racchiuse tra graffe, es: "{NORMBATCH.ArcDati} select * from AnagraficaClienti" un esempio si vede bene e si puo seguire in ShowAnagrafica in Tabelle.js function ShowAnagrafica() { var q = "{NORMBATCH.ArcDati} select * from AnagraficaClienti"; var url = CreateAjaxCall('GRID', 'QUERY3;' + q); cpAjax('listTable',url); } questi metodi istanziano il mapper SQLMapper e una serie di oggetti da cui ricavano tabella, schematable, datatable, rows, cells e tutto quello che serve di una query, suggerisco di dare un occhiata a SQLData SQLRow SQLRequest che sono una figata devo definire la scrittura su disco, la serializzazione, che quando l'ho provata non si poteva fare piu du un tot di bytes, andava in eccezione, ma si puo fare, basta non fare come facevo all'inizio che volevo scrivere su disco l'intero oggetto in cascata serializzando SQLData anche se era il risultato di una query di 20GB si puo fare, se si serializza row per row, accoda, non schianta aggrovigliolandosi nei banchi di ram. ======= da settembre è stato implementato un 4° tipo di griglia, con template pulsanti per editing, title, ecc arriva da ajax QUERY4, vars contiene una serie di parametri e la query

Page 38: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

* @catalog:NORMBATCH.ArcDati @template:null @title:Punti Posta @button:mode=select, Title=seleziona il punto posta, callback=SelectItemPPA(%nomecolonna%) @footerStat:true" @totalizeColumn:c1 @query: <sql statements>" Live Update (edit di un campo dopo selezione di un valore su un dropdown di una cella di una griglia utilissimo per le combo sulla grid che si vuole rendere 'live update' quando seleziono il valore scrive anche sul db vedi in citypost.js fa tutto da se il generatore di dropdown, segui le istruzioni di questa function function DD_MakeSelection(span_id, text) ti guida in tutti i passaggi che fa, per poterla riutilizzare in altre pagine TIP & TRICKS - Debug 1) se vuoi controllare ogni singolo url che viene passato ad ajax, attiva var WatchDogEnabled = true; in citypost.js, questo fara si che ad ogni call visualizzi un msg info sulla pagina con l'url PERMESSI SETTINGS e ABILIZATIONI

Page 39: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

ogni utente è abilitato a qualcosa attraverso la combinazione dei ruoli e i legami che questi hanno nella definizione dei permessi un ruolo puo avere piu funzionalita, quindi ci saranno n records su permessi che ne descrivono e stabiliscono regole e parametri un rk permesso puo essere di tipo redirect, che a seconda della combinazione dei ruoli redirige il login su una pagina specifica o un FOLDER, che impedisce ad altri ruoli (non definiti nel record) di accedervi oppure feature o settings (è uguale) le relazioni tra ruoli, permessi e impostazioni è fatta da keyword un setting puo essere condiviso da piu ruoli esempi pseudo code ruolo A ------ > redirect su pagina A ruolo A e B ---> redirect su pagina B ruolo A -------> permesso di accedere a folder A ruolo A -------> feature APP1 key A1 ruolo B -------> perm KEY-P1 perm KEY-P2 setting KEY-S1 KEY-S2 P EX1 viene aggiunto se ruolo Extranet e Agenzia Per attivare una nuova funzionalita, ad esempio, il TELEX, che le abilitazioni sianiano amministratate da ADMIN per i clienti Direzionali a Agenzie, mentre amministrate per le agenzie servono questi record 1 rk su permsessi TLX0; any,roles,allow; Cliente Direzionale,Agenzia own: any Admin 1 rk su SWSettings EXANLED predefinito true

Page 40: *XLGD DOOD FUHD]LRQH GL XQD :HE $SSOLFDWLRQ ....../H WHFQLFKH XWLOL]]DWH VRQR VWDWH WUDWWH GD 3URIHVVLRQDO $63 1(7 LQ & DQG 9% QHOO\ SGI ,O 3') GL 0E H SDJLQH FRQWLHQWH WXWWR TXHOOR

sull'html, per mostrare l'icona bastera usr.profileGetBool("ENABLED,true,"TLX0") su vuoi che tutte le agenzie vedono i telex meno milano3, vai da admin su milanor, ENABLED lo metti a false, e il gioco è fatto, tutti meno milano3 possono gestire i telex TEMPLATES I templates sono tutti in \Templates e evitano di scrivere da codice tag html. offrono il grosso vantaggio che sono modificabili anche a sito pubblicato in quanto asp.net renderizza sul server quello che piace a lui, i tag <asp:xx sono renderizzati in corrispettivi tag html quindi tutto asp.net passa dal compilatore e ogni modifica richiede la ripubblicazione. i templates permettono di far fare al codice quello che serve che sia fatto sul server, e il contenuto delle pagine non le decide aspx, ma noi. vengono renderizzate ad ogni chiamata, quindi se si modificano cambia la pagina all'istante. La classe TemplateHelper è l'oggetto che gestisce e renderizza questi files. SailWeb funge da CORE statico, e contiene tutte le funzioni comuni a tutti gli utenti che non accedono a BL o dati, non fanno transazioni SailNetStorage è una classe non statica ma dichiarata statica in SailWeb. Era nata con scopi diversi , doveva agganciare il mondo SailNet, un altra CityPostStorage idem, ecc. E' rimasta come interfaccia tra sito e BL/Dati le sottoclassi RoyMember e Administrator, sono istanziate solo se i ruoli ne hanno bisogno, ma essendo statica a livello globale, cosi com'è fatta non sa nessun senso la ottimizzeremo