-----------------------------------

Acquista i software ArcGIS tramite Studio A&T srl, rivenditore autorizzato dei prodotti Esri.

I migliori software GIS, il miglior supporto tecnico!

I migliori software GIS, il miglior supporto tecnico!
Azienda operante nel settore GIS dal 2001, specializzata nell’utilizzo della tecnologia ArcGIS e aderente ai programmi Esri Italia Business Network ed Esri Partner Network

-----------------------------------



martedì 27 gennaio 2009

IDisposable

Il principale scopo di questa interfaccia è fornire un metodo per rilasciare risorse non gestite.

Il garbage collector rilascia automaticamente la memoria allocata per un oggetto gestito quando non è più utilizzato. Comunque non è possibile prevedere quando il garbage collector entrerà in azione. Inoltre il garbage collector non conosce risorse non gestite come ad esempio window handles, streams ecc.

Utilizzando il metodo Dispose di questa interfaccia esplicitamente rilasciamo risorse non gestite in congiunzione con il garbage collector. Chi utilizza un oggetto può chiamare questo metodo quando l'oggetto non è più necessario.

Utilizzando lo using si renderà ancora più semplice ed efficace la chiamata al dispose piuttosto che utilizzare il pattern try/finally per essere sicuri che le risorse non gestite siano disposte anche in presenza di eccezione.


using System;

using System.ComponentModel;

 

// Il seguente esempio dimostra come creare

// una classe che implementa l'interfaccia IDisposable

// e il metodo IDisposable.Dispose.

 

public class DisposeExample

{

    // Una classe base che implementa IDisposable.

    //implementando IDisposable stai dichiarando che le istanze

    //allocheranno delle risorse

    public class MyResource : IDisposable

    {

        // Puntatore ad una risorsa non gestita

        private IntPtr handle;

 

        //Altra risorsa gestita dalla classe

        private Component component = new Component();

 

        // Tracci se il metodo dispose è stato chiamato

        private bool disposed = false;

 

        // Il costruttore della classe

        public MyResource(IntPtr handle)

        {

            this.handle = handle;

        }

 

        // Implementa IDisposable.

        // Non dichiarare il metodo virtuale

        // Una classe derivata non è abilitata a fare l'override questo metodo.

        public void Dispose()

        {

            Dispose(true);

 

            // Questo oggetto sarà rilasciato dal metodo dispose

            // Inoltre chiamerai GC.SupressFinalize per portare

            // fuori dalla coda di finalizzazione e prevenire che

            // il codice di finalizzazione per questo oggetto

            // sia eseguito una seconda volta

            GC.SuppressFinalize(this);

        }

 

 

        // Per Dispose(bool disposing) ci sono due distinti scenari.

        // Se disposing è uguale a true il metodo è stato chiamato direttamente

        // o indirettamente dal codice dell'utente. Risorse gestite e non possono

        // essere disposte.

        // Se disposing è uguale a false il metodo è stato chiamato dal runtime

        // dall'interno del finalizzatore e non dovresti riferire ad altri oggetti.

        // Soltanto risorse non gestite possono essere disposte.

        private void Dispose(bool disposing)

        {

            // Controlla se il dispose è stato chiamato

            if (!this.disposed)

            {

 

                // Se disposing è uguale a true, disponi tutte le risorse gestite e non

                if (disposing)

                {

                    // Dispone risorse gestite.

                    component.Dispose();

                }

 

                // chiama l'appropriato metodo per rilasciare risorse non gestite.

                // Se il disposing è uguale a false solo il questo codice è eseguito

                CloseHandle(handle);

                handle = IntPtr.Zero;

 

                // notifica che il dispose è stato fatto

                disposed = true;

 

            }

        }

 

        // Usa interop per chiamare il metodo necessario

        // per rilasciare risorse non gestite

        [System.Runtime.InteropServices.DllImport("Kernel32")]

        private extern static Boolean CloseHandle(IntPtr handle);

 

        // Usa la sintassi di C# per i distruttori per finalizzare il codice.

        // Questo distruttore viene eseguito solo se il metodo

        // dispose non è stato chiamato

        // Dà la possibilità la classe base l'opportunità di finalizzare.

        // Non fornire distruttori nei tipi derivati da questa classe.

        ~MyResource()

        {

 

            // Chiamando Dispose(false) è ottimale in termini di leggibilità e manutenibilità

            Dispose(false);

        }

    }

    public static void Main()

    {

 

        IntPtr i = new IntPtr(25);

        using (MyResource myResource = new MyResource(i))

        {

 

        }

        //le risorse dell'istanza sono disposte automaticamente

    }

}




In .NET, la gestione degli oggetti COM è fatta mediante il runtime callable wrappers (RCWs), cioè oggetti gestiti che si attuano come oggetti proxy per trattenere gli oggetti com sottostanti.

Il .NET garbage collector rilascia in modo non deterministico gli oggetti gestiti dalla memoria, però nel caso in cui gli oggetti com trattengono risorse di sistema (file handles, connessione al database ecc.) devi esplicitamente rilasciare gli oggetti com per liberare le risorse trattenute da essi.

Per liberare gli oggetti com sotto l'RCW dalla memoria in modo deterministico è possibile utilizzare il ReleaseComObject.
Chiamando il ReleaseComObject decrementeremo il contatore del reference trattenuto dall'rcw. Una volta che il contatore del reference ha raggiunto lo zero (potrebbe essere richiesto chiamare il metodo più volte) l'rcw è segnato per la garbage collection. Se gli oggetti com non trattengo altri oggetti com il runtime com rilascera l'oggetto com stesso.

 private void MyFunction()

        {

            ESRI.ArcGIS.Display.IStyleGallery styCls = new

              ESRI.ArcGIS.Framework.StyleGalleryClass() as

              ESRI.ArcGIS.Display.IStyleGallery;

            // Use the StyleGalleryClass here.

            int refsLeft = 0;

            do

            {

                refsLeft = Marshal.ReleaseComObject(styCls);

            }

            while (refsLeft > 0);

        }



Utilizzato oggetti come i cursori che utilizzano risorse è importante rilasciarli non appena si è finito di utilizzarli e non dover aspettare che entri in azione la garbage collector poichè i cursori trattenendo risorse (data source) potrebbero bloccare l'applicazione fino a che non siano rilasciati i cursori.
Si pensi all'sde datasource, i cursori trattengono l'sde stream e se l'applicazione ha tanti client, ognuno potrebbe trattenere un sde stream esaurendo ad esempio il massimo numero consentito di stream.

for (int i = 1; i < 2500; i++)

            {

              IQueryFilter qu = new QueryFilterClass();

              qu.WhereClause = @"Area = " + i.ToString();

              IFeatureCursor featCursor = featClass.Search(qu, true);

 

              System.Runtime.InteropServices.Marshal.ReleaseComObject(featCursor);

            }


In ArcGis server per assicurare che l'oggetto com sia rilasciato fuori dal suo scopo abbiamo una oggetto di helper chiamato WebObject.
Usa il metodo ManageLifeTime per aggiungere il tuo oggetto com ad un insieme di oggetti che saranno rilasciati esplicitamente quando il webobject è disposto.


using (WebObject webobj = new WebObject())

            {

                ServerConnection serverConn = new ServerConnection("doug", true);

                IServerObjectManager som = serverConn.ServerObjectManager;

                IServerContext ctx = som.CreateServerContext("Yellowstone", "MapServer");

                IMapServer mapsrv = ctx.ServerObject as IMapServer;

                IMapServerObjects mapo = mapsrv as IMapServerObjects;

                IMap map = mapo.get_Map(mapsrv.DefaultMapName);

                IFeatureLayer flayer = map.get_Layer(0) as IFeatureLayer;

                IFeatureClass fclass = flayer.FeatureClass;

                IFeatureCursor fcursor = fclass.Search(null, true);

                webobj.ManageLifetime(fcursor);  //aggiungo il cursore

                IFeature f = null;

                while ((f = fcursor.NextFeature()) != null)

                {

                    // Do something with the feature.

                }

                ctx.ReleaseContext();

            }



//fuori dallo scopo il cursore è rilasciato poichè l'oggetto webobj è disposto



Il ComReleaser ha la stessa funzione del webObject. Può essere utilizzato con l'engine ( ComReleaser Gestione del ciclo di vita dei cursori ).

Altri oggetti importanti da rilasciare sono i Singletons (oggetti che hanno una sola istanza per processo) per non lasciare processi come pinning cioè pendenti. ( lista oggetti singleton )

sabato 10 gennaio 2009

Ottimizzazione delle prestazioni in applicazioni web ADF

Sia che tua abbia sviluppato un'applicazione web .NET ADF dal Manager o che tu l'abbia costruita da zero in Visual Studio, ci sono diverse opzioni per migliorare le prestazioni.

- Fai la cache dei tuoi servizi di mappa

Facendo la cache dei tuoi servizi di mappa, ridurrai il tempo che ci vuole per visualizzare la tua mappa. Quando possibile, cerca di fare la cache di tutti i servizi nella tua applicazione e di non combinare servizi con cache e senza cache. Nella versione 9.3 la visualizzazione di mappe dove servizi dinamici e con cache sono stati combinati insieme è stata notevolmente ottimizzata.

- valuta il formato dell'immagine per la tua mappa con cache

Il formato predefinito dell'immagine per tool di caching nella versione 9.2 è in PNG24. Usando un formato d'immagine differente, come PNG8 o JPEG, si può avere una dimensione del file dell'immagine più piccola ed una più veloce visualizzazione delle immagini in un controllo di mappa. Nota che alla versione 9.3 il formato di default per la cache è ora in PNG8.

Evita di usare Internet Explorer 6 quando l'applicazione web contiene più servizi cachati in formato PNG24, dato che Internet Explorer 6 ha una capacità limitata di visualizzare la trasparenza per immagini in formato PNG24. Il web ADF include del codice che aggira questo limite, ma c'è un peggioramento della prestazione quando si incontra tale situazione. Evita così questa situazione:

a) Usando Internet Explorer 7 o Firefox 2 quando visualizzi servizi fusi con cache in formato PNG24.

b) Fai la cache dei tuoi servizi di mappa in formato PNG8, PNG32 o JPEG se deve essere utilizzato Internet Explorer 6.

- usa connessioni ArcGIS Server Internet quando possibile

Connettiti al tuo server utilizzando connessioni ArcGIS Server Internet per fare un uso più efficiente delle richieste al server context. Le connessioni ad ArcGIS Server Local dovrebbero essere usate solo quando l'applicazione richiede di lavorare con gli ArcObjects sul server. Questo comporta cambi significativi al servizio e l'utilizzo di funzionalità solo disponibili negli ArcObjects.

-Utilizza la nuova proprietà 'StaticMode' dell'Overviewmap

L'OverviewMap è stata migliorata dal Service Pack 5 della 9.2, che include anche una nuova proprietà: StaticMode. Impostando StaticMode a True, l'immagine nell'OverviewMap non cambia quando cambia l'estensione della mappa. Precedentemente veniva generata una nuova immagine per l'OverviewMap ogni volta che l'estensione della mappa cambiava.


- ottimizza il controllo della tabella dei contenuti (TOC)

Il Service Pack 3 della versione 9.2 risolve un significativo problema di prestazione con il controllo della TOC. Questo problema era particolarmente sentito quando si usavano servizi di mappa con un numero notevole di layer, gruppi di layer e layer con impostata una scala di visualizzazione.

Il controllo della TOC ha diverse opzioni che consentono allo sviluppatore di ridurre la quantità di informazioni rihiesta dal server.

TOCType: l'impostazione di default ('SwatchList') genererà una TOC che elenca sia il nome del layer che la simbologia. Cambiando questa impostazione a 'LayerList' ridurremo la quantità di informazioni richiesta dal server solo visualizzando i nomi dei layer e non la simbologia.

RenderOnDemand: quando si configura una TOC per visualizzare la simbologia, impostando questa proprietà a True ritarderemo la richiesta di informazioni fino a che un layer è espanso nell'albero della TOC. Questo aiuterà a migliorare il tempo di startup iniziale dell'applicazione.

ExpandDepth: usa un valore di ExpandDepth di 0 o 1 per minimizzare il numero di layer nidificati visibili quando la TOC è visualizzata allo startup iniziale dell'applicazione.

Considera di impostare la proprietà di Visible su alcuni dei tuoi MapResourceItems a False. Questo comporterà un caricamento più veloce dell'applicazione ma l'utente della pagina web dovrà rendere visibili i layer manualmente.


- Elimina dalla tua applicazione i controlli web che non sono assolutamente necessari
L'Applicazione predefinita di Web Mapping che viene creata col Manager e Visual Studio include controlli web come la tabella dei contenuti (TOC), l'OverviewMap e la Scalebar. Quando interagisci con la tua applicazione, questi controlli richiedono nuove immagini ed un aggiornamento continuo di stato. Eliminare dall'applicazione i controlli che vengono raramente usati migliora la prestazione dell'applicazione e la scalabilità del sistema.

- messa in produzione delle applicazioni senza debug

I controlli web ADF emettono JavaScript richiesto per l'utilizzo dai controlli ADF. Quando metti la tua applicazione in ambiente di produzione, rimuovi l'opzione di debug (dal web.config) per assicurarti che la versione compressa dei file web ADF JavaScript
siano inviati al client. Ciò ridurrà il tempo di caricamento iniziale dell'applicazione.

- usa Compressione HTTP

IIS fornisce la possibilità di comprimere risorse, per esempio JavaScript inviata al browser del client a runtime. La compressione ridurrà la quantità di informazioni da fornire al client (di solito al caricamento iniziale).

- disabilita dati mime

In modo predefinito, le risorse di mappe senza cache nel web ADF generano immagini mime che sono inviate al browser per la visualizzazione. Per ridurre la quantità di informazioni che deve essere elaborata direttamente dall'ADF, disabilita l'uso di dati mime sulla risorsa ('request mime data' nella finestra di modifica delle impostazioni della visualizzazione della risorsa di mappa). L'url all'mmagine della mappa generato dal servizio di mappa deve essere disponibile in una directory virtuale pubblica. Durante la visualizzazione della mappa a runtime, il browser restituirà l'immagine via url invece che leggendo e restituendo il flusso mime. Da notare che la trasparenza applicata alla risorsa di mappa non sarà applicata in questa situazione. La trasparenza di sfondo verrà rispettata se il tipo di immagine generato dal servizio di mappa lo supporta (ad esempio, png).

- definisci il nome del data frame per i servizi ArcGIS Server

La definizione della risorsa per una risorsa ArcGIS Server include il nome del data frame e del servizio di mappa. Se il nome del data frame è '(default)', l'applicazione ADF deve richiedere il nome del data frame predefinito dal servizio di mappa quando la risorsa è inizializzata (possibile ad ogni richiesta). Se il nome del data frame è dichiarato esplicitamente si evitano ulteriori richieste.

- uso di ArcGIS Server LayerDescription per migliorare i tempi di risposta delle interrogazioni

Ogni risorsa di mappa di ArcGIS Server nell'ADF ha un MapDescription che mantiene una lista di descrizioni dei layer come un array LayerDescription, MapDescription e LayerDescription sono tipi definiti dall'ArcGIS Server SOAP API. Un LayerDescription descrive i contenuti di un layer in un servizio di mappa. Quando si interrogano i layer in un servizio di mappa di ArcGIS Server usando tipi ADF (per esempio IQueryFunctionality) viene usato l'ArcGIS Server SOAP API. Come risultato, le modifiche ai tipi SOAP associati con una risorsa di mappa ArcGIS Server possono variare i risultati dell'interrogazione. In molti casi, restituendo la geometria da un'interrogazione, è necessario disegnare le feature in una mappa come una selezione o un sottoinsieme. Il livello di dettaglio in una geometria restituita (per esempio numero dei vertici) influenzerà direttamente la mole di tempo che ci vuole per restituire un risultato. In modo predefinito, la geometria verrà restituita completamente così come è stata memorizzata. Se non è necessario un dettaglio completo, puoi generalizzare la geometria restituita da un'interrogazione usando l'oggetto GeometryResultOptions associato ad un LayerDescritpion. Generalizzare la geometria ridurrà la quantità di tempo che ci vuole ad un'interrogazione per restituire un risultato.

GeometryResultOptions definisce due proprietà che interessano questo caso: GeneralizeGeometry e MaximumAllowableOffset. Imposta GeneralizeGeometry a true e definisci un MaximumAllowableOffset in unità di mappa. Il MaximumAllowableOffset definisce la massima distanza della geometria di output dalla geometria di input. Più grande è il valore, maggiore è la generalizzazione della geometria. Dal momento che il MapDescription per una risorsa di mappa ArcGIS Server è memorizzata nello stato durante una sessione, quando cambi questo valore esso viene mantenuto per tutta questa durata.
Per reimpostare o disabilitare, modifica manualmente le proprietà o imposta GeneralizeGeometry a false. Il seguente blocco di codice fornisce un esempio di come impostare queste proprietà usando un MapFunctionality ArcGIS Server e un LayerDescription SOAP API nel web ADF. Dopo aver impostato tali valori per un LayerDescription, restituisci la geometria da una chiamata al metodo ADF QueryFunctionality.Query. Le geometrie ADF nei risultati (ADF FeatureGraphicsLayer) saranno generalizzate.


ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality agsMapFunctionality =
(ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality)mapFunctionality;

ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription[] layerDescriptions =
agsMapFunctionality.MapDescription.LayerDescriptions;

ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription activeLayerDescription =
ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapFunctionality.GetLayerDescription(
activeLayerIDInt, layerDescriptions);

activeLayerDescription.LayerResultOptions.GeometryResultOptions.GeneralizeGeometries = true;
activeLayerDescription.LayerResultOptions.GeometryResultOptions.MaximumAllowableOffset = 10000;



- bypassa la creazione di child control in un custom control

Quando crei controlli server custom per usarli con il web ADF, come ad esempio i task, il controllo spesso contiene una collezione di child control come pulsanti, textbox, tabelle ecc. Ogni richiesta alla pagina itera attraverso il ciclo di vita della pagina e dei controlli i quali includono la creazione di ogni controllo e dei suoi figli. Se una richiesta non viene processata dal tuo custom server control, puoi saltare la creazione dei controlli figlio. Il modo più semplice è aggiungere alcune condizioni al metodo CreateChildControls del tuo custom server control (di solito la posizione in cui i controlli figlio sono creati e aggiunti alla collezione del controllo padre). Sotto presentiamo due situazioni. Entrambe usano una utility class, AsyncOptimizer, per determinare il chiamante in una richiesta async e stabilire se il CreateChildControls in un custom control verrà completamente eseguito. La classe AsyncOptimizer è inclusa nell'esempio dell'SDK Common CustomTasks, nel controllo OptimizerTask.

1° caso: semplice custom task senza child control che genera chiamate async


protected override void CreateChildControls()
{
base.CreateChildControls();

#region Do not create child controls in an async call if this control is not participating in the call

AsyncOptimizer asyncOptimizer = new AsyncOptimizer(this);
if (!asyncOptimizer.RequiresChildControls)
return;

#endregion



2° caso: custom task con child control e tools che genera chiamate async


protected override void CreateChildControls()
{
base.CreateChildControls();

#region Do not create child controls in an asyn call if this control is not participating in the call

AsyncOptimizer asyncOptimizer = new AsyncOptimizer(this);
if (!asyncOptimizer.RequiresChildControls)
return;

#endregion

#region Create Child Controls



#endregion

#region Register child controls that can handle async calls
//Child controls that handle async calls

asyncOptimizer.ChildControlsHandlingAsyncCalls.Clear();
asyncOptimizer.ChildControlsHandlingAsyncCalls.Add(treeviewPlus.UniqueID);

//Map tools on this control

asyncOptimizer.MapToolsHandlingAsyncCalls.Clear();
asyncOptimizer.MapToolsHandlingAsyncCalls.Add(tlAddFeatures.Name);

#endregion
}