tag:blogger.com,1999:blog-83230718611230248822024-03-13T04:25:28.782+01:00NicoGis - Sviluppare in ambiente ArcGIS...Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.comBlogger112125tag:blogger.com,1999:blog-8323071861123024882.post-77814895045892449712016-03-10T19:22:00.000+01:002018-12-26T14:10:08.311+01:00La sicurezza prima di tutto!A partire da ArcGIS Server 10.4 abbiamo a disposizione un tool da eseguire da riga di comando chiamato <i><b>serverScan.py</b></i>. Il tool esegue la scansione del tuo site ArcGIS Server per verificare se è stato configurato seguendo le best practise raccomandate da Esri per quel che riguarda la sicurezza.<br />
Il tool è presente nella cartella<br />
<br />
<div style="text-align: center;">
<i>C:\Program Files\ArcGIS\Server\tools\admin</i></div>
e, una volta eseguito, restituisce un report html. <br />
Come potete notare dall'estensione del file è un tool scritto in Python.<br />
Analogamente è presente un tool chiamato <i><b>portalScan.py</b></i> ( ..\Portal\tools\security) che controlla la configurazione del Portal per verificare che siano rispettate le best practise raccomandate da Esri.<br />
<br />
Qui potete vedere un esempio di report generato dal tool.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPmynAymrtXkhuOvsyWxK2CZXyGTP9fFwOwNHm96ZDeInLGDUVdn2xR473S-iTwMLg7vDZGoAFGEAaAEkt1j0ZO9wCwiAW4Z8peTvkvylgCW2K_YqMRI3rSRkIZUev8LhnF9kWNAqJqMoH/s1600/spdt1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPmynAymrtXkhuOvsyWxK2CZXyGTP9fFwOwNHm96ZDeInLGDUVdn2xR473S-iTwMLg7vDZGoAFGEAaAEkt1j0ZO9wCwiAW4Z8peTvkvylgCW2K_YqMRI3rSRkIZUev8LhnF9kWNAqJqMoH/s640/spdt1.jpg" width="640" /></a></div>
<br />
Il tool analizza 12 problematiche legate alla sicurezza dividendole in tre livelli di severità: critico, importante e raccomandato. <a href="http://server.arcgis.com/en/server/latest/administer/linux/scan-arcgis-server-for-security-best-practices.htm" target="_blank">Qui</a> potete trovare l'elenco.<br />
<br />
I parametri da passare al tool sono il nome completo della macchina, la user/password dell'admin del site e la cartella di output dove generare il report.<br />
<br />
Con ArcGIS Server federato è possibile anche passare il token (-t in riga di comando) generato dal portal da https://mydomain/portal/sharing/rest/generateToken con Client impostato a <b><i>Webapp URL </i></b>al nome del dominio (esempio https://mydomain ) al posto della user/password del PSA<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO7SilGnsC1caImGLrshs1dYeej_ghNumxVuHM8YihNJ7CAT1fXP_SiU3re8EXXIdg-R6_0TBuxmztvo4nNxkP_UtHKUAbAOwxn6uurPmVOSyQBYJowfA5sQThlcgIqQ25f7dOjqcKsa6j/s1600/spdt2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="274" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO7SilGnsC1caImGLrshs1dYeej_ghNumxVuHM8YihNJ7CAT1fXP_SiU3re8EXXIdg-R6_0TBuxmztvo4nNxkP_UtHKUAbAOwxn6uurPmVOSyQBYJowfA5sQThlcgIqQ25f7dOjqcKsa6j/s640/spdt2.png" width="640" /></a></div>
Mentre, se si genera il token dall'administrator directory di ArcGIS Server ( arcgis/admin/generateToken ), occorre impostare per il Client <b><i>Request IP</i></b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3BcJbgMC3cRzzlupdUsMqiIBgJ2frpITWeKxoaxlq0p0dGIHs_4ade6Flar9Pe7794ll2cuYxLYM9XHmwHgZ0AMvSpbspry9QbUuoQcA1PWoRJpU2eO6DcVl6jm3rMlERnkcJynTkUsDN/s1600/spdt3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="472" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3BcJbgMC3cRzzlupdUsMqiIBgJ2frpITWeKxoaxlq0p0dGIHs_4ade6Flar9Pe7794ll2cuYxLYM9XHmwHgZ0AMvSpbspry9QbUuoQcA1PWoRJpU2eO6DcVl6jm3rMlERnkcJynTkUsDN/s640/spdt3.PNG" width="640" /></a></div>
<br />
<br />
Esempio:<br />
<br />
<div style="text-align: center;">
<span class="usertext"><i><b>python serverScan.py -n gisserver.domain.com -u admin -p mypassword -o C:\Temp</b></i></span></div>
<div style="text-align: justify;">
<span class="usertext"><br /></span></div>
<div style="text-align: justify;">
<span class="usertext"><br /></span></div>
<div style="text-align: justify;">
<span class="usertext">Vediamo ora nel dettaglio i criteri che vengono verificati:</span></div>
<div style="text-align: justify;">
<span class="usertext"><br /></span></div>
<div style="text-align: justify;">
<span class="usertext"><span style="color: red; font-size: large;">SS01 Critico</span><b></b></span></div>
<div style="text-align: justify;">
<span class="usertext">Verifica se la comunicazione con ArcGIS Server è criptata su canale ssl derminando se è abilitato l'https. Se il web adaptor è installato è raccomandato che la comunicazione sia protetta.</span><br />
In questo caso viene evidenziato che la connessione avviene solo in http con arcgis server.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigNRvvt-KaC9AhzqF8NSTDoZy4CPRH6LPLa4CONOa9QiAOFklL7lKR7sF2J5l-ECi7fAZ2L1YLu1l2OK1SX5QZG9mooA7GUPESmJhAa683U0OjZAwMjV4SiYxQFnwVkWX7A4lGl_Luw2S-/s1600/SPDT0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="486" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigNRvvt-KaC9AhzqF8NSTDoZy4CPRH6LPLa4CONOa9QiAOFklL7lKR7sF2J5l-ECi7fAZ2L1YLu1l2OK1SX5QZG9mooA7GUPESmJhAa683U0OjZAwMjV4SiYxQFnwVkWX7A4lGl_Luw2S-/s640/SPDT0.png" width="640" /></a></div>
<br /></div>
<div style="text-align: justify;">
Inoltre abbiamo la possibilità di specificare i protocolli SSL. I predefiniti ArcGIS Server sono il TLS v1.0, TLS v1.1 e il TLS v1.2. Sono stati tolti SSL 2.0 e SSL 3.0 perché obsoleti e insicuri. Se decidiamo di abilitare solo il TLS v1.2 - attualmente il più sicuro in base ai cifrari utilizzati e comunque quello che supporta le criptazioni autenticate più moderne (ad esempio AEAD) - occorrerà verificare il web server che ospita il web adaptor possa comunicare con il TLS 1.2. Il TLS v1.0 è un protocollo legacy che viene ancora utilizzato ma, se possibile, è meglio evitarlo visto che anche se i moderni browser mitigano le sue debolezze presenta comunque problemi.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Per disabilitare SSL2 e SSL3 in Windows occorre </div>
<div style="text-align: justify;">
<br /></div>
<blockquote class="tr_bq">
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel\Protocols\SSL 2.0\Client]<br />
“DisabledByDefault”=dword:00000001<br />
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel\Protocols\SSL 2.0\Server]<br />
“Enabled”=dword:00000000<br />
<br />
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel\Protocols\SSL 3.0\Client]<br />
“DisabledByDefault”=dword:00000001<br />
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel\Protocols\SSL 3.0\Server]<br />
“Enabled”=dword:00000000</blockquote>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Inoltre è raccomandato disabilitare l'algoritmo di cifratura RC4 che è insicuro</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 128/128]<br />
"Enabled"=dword:00000000 </div>
<div>
<br /></div>
<div>
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 40/128]<br />
"Enabled"=dword:00000000</div>
<div>
<br /></div>
<div>
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 56/128]<br />
"Enabled"=dword:00000000 </div>
<div>
<br /></div>
<div>
Per disabilitare Diffie-Hellman vedi questo <a href="https://www3.trustwave.com/support/kb/Article.aspx?id=14784" target="_blank">articolo</a>.</div>
<div>
<br /></div>
<div>
Inoltre dovrebbe essere evitate le seguenti obsolete primitive crittografiche:</div>
<div>
- Anonymous Diffie-Hellman (ADH) non forniscono autenticazione;</div>
<div>
- NULL cipher non forniscono crittografia.<br />
- Export cipher sono insicuri quando negoziati in una connessione, ma possono anche essere utilizzati con server che preferiscono cipher forti<br />
- cipher deboli (tipicamente di 40 e 56 bits) usano crittografia che può essere decifrata.<br />
- 3DES è lento e debole.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Questa potrebbe essere un buon punto di partenza come sequenza di cifratori da utilizzare</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256<br />
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384<br />
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA<br />
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA<br />
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256<br />
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384<br />
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256<br />
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384<br />
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA<br />
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA<br />
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256<br />
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384<br />
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256<br />
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384<br />
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256<br />
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384<br />
TLS_DHE_RSA_WITH_AES_128_CBC_SHA<br />
TLS_DHE_RSA_WITH_AES_256_CBC_SHA<br />
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256<br />
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Purtroppo di cifrari occorre prevederne più di uno per la retrocompatibilità con i client che utilizzano il servizio e pertanto, per garantire la compatibilità, occorre trovare il miglior compromesso di <a href="https://blogs.technet.microsoft.com/askds/2015/12/08/speaking-in-ciphers-and-other-enigmatic-tonguesupdate/" target="_blank">suite di priorità di ordine</a>.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Se volete testare il vostro ssl utilizzate l'indirizzo: <a href="https://www.ssllabs.com/ssltest/analyze.html" target="_blank">ssllabs</a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Per ricevere un rating A+ su sistemi windows occorre avere solo abilitato il TLS 1.2 e <a href="https://it.wikipedia.org/wiki/HTTP_Strict_Transport_Security" target="_blank">l'HSTS</a> (vedi questo <a href="https://www.tbs-certificates.co.uk/FAQ/en/hsts-iis.html" target="_blank">articolo</a> per abilitarlo su IIS)</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigYxkwq-c4fZJDLqi2RewWyviI4SxnQTbxwSjkJ4LuaXzjaeeWLe3dgLSITMxgbp4sXRwWslhuiIvHZeCwN7fBUEEByi3wsryyVv1sRQ7haL1-GcPmRBBjA9sTW0llZs3P88T2howTFUUL/s1600/SPDT18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigYxkwq-c4fZJDLqi2RewWyviI4SxnQTbxwSjkJ4LuaXzjaeeWLe3dgLSITMxgbp4sXRwWslhuiIvHZeCwN7fBUEEByi3wsryyVv1sRQ7haL1-GcPmRBBjA9sTW0llZs3P88T2howTFUUL/s640/SPDT18.png" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="text-align: justify;">
<span class="usertext"><span style="color: red; font-size: large;">SS02 Critico</span></span></div>
<div style="text-align: justify;">
<span class="usertext">Verifica se le query standardizzate sono imposte da ArcGIS Server. Per fornire protezione ad attacchi di <a href="https://it.wikipedia.org/wiki/SQL_injection" target="_blank">SQL injection</a> - essendo tale livello considerato critico - l'opzione è abilitata e ArcGIS Server verifica le query non consentendo di utilizzare specifiche funzioni e sintassi del database sottostante. </span></div>
<div style="text-align: justify;">
<span class="usertext"><a href="http://server.arcgis.com/en/server/latest/administer/linux/supported-sql-functions-in-arcgis-server.htm" target="_blank">Qui</a> puoi vedere come utilizzare le funzioni con query standardizzate. </span></div>
<div style="text-align: justify;">
<span class="usertext">Se non presente, è abilitato mentre se occorre disabilitarlo bisogna dichiararlo in <i>system->properties</i></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCTNdex8DWkSgS_BY6jdWTtQDatOH3whHBkcZedPahPvq6QFz7NXmRwXKHdGDc6RcFm28N0HBliutOctZPnm7GZdd7aAI_cR-MWoQ8qm_LBG3PB43uj510T5axqPa6yP3UcQpF1axpBZRj/s1600/spdt5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="490" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCTNdex8DWkSgS_BY6jdWTtQDatOH3whHBkcZedPahPvq6QFz7NXmRwXKHdGDc6RcFm28N0HBliutOctZPnm7GZdd7aAI_cR-MWoQ8qm_LBG3PB43uj510T5axqPa6yP3UcQpF1axpBZRj/s640/spdt5.png" width="640" /></a></div>
<div style="text-align: justify;">
<span class="usertext"><br /></span><span class="usertext" style="color: red; font-size: large;">SS03 Critico</span></div>
<div style="text-align: justify;">
<span class="usertext">Verifica se la generazione del token via GET è supportata. Quando viene generato il token via GET le credenziali sono inviate come parte dell'URL e possono così essere visualizzate attraverso la history del browser o i log della rete. <b><u>Dovrebbe essere disabilitato</u></b> a meno che sia richiesto esplicitamente da altre applicazioni. Se non presente, è false altrimenti occorre dichiararlo in <i>security->tokens. </i>L'impostazione predefinita è false.</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwyREdwp_NsZPyjwFy4VqD6ndworek1Lwb_xe0Wy0LsYQp-B-yDoiBi1YJ8saih1mtro3X-C35ZmZn9Z4vrxtuC2Mv80xKp__6ZEABMpXQc_DqNwwQBAb7tgyUYplq_WYXySMZtAAaTvJd/s1600/spdt6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwyREdwp_NsZPyjwFy4VqD6ndworek1Lwb_xe0Wy0LsYQp-B-yDoiBi1YJ8saih1mtro3X-C35ZmZn9Z4vrxtuC2Mv80xKp__6ZEABMpXQc_DqNwwQBAb7tgyUYplq_WYXySMZtAAaTvJd/s640/spdt6.png" width="640" /></a></div>
<br />
<span style="color: red; font-size: large;">SS04 Critico</span><br />
Verifica se la generazione del token via POST con le credenziali nei parametri della query string è supportata. Le problematiche sono le stesse dell'SS3 e pertanto andrebbe disabilitato. Se non presente è false altrimenti occorre dichiararlo in <i>security->tokens. </i>L'impostazione predefinita è false.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYid6fOMgefZu8e6a6zCz5vwtJ2M0SDAoWHY65Sn6jHPjrZW9Yki_LDPpjLZ6mVjri0V5PLZQEeo2KpE2BYKSKh7Y6Yj84tjJprosMKjL2Lt0iNvdWR4awPGb-b4fUY999N5h-JToN3TpI/s1600/spdt7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYid6fOMgefZu8e6a6zCz5vwtJ2M0SDAoWHY65Sn6jHPjrZW9Yki_LDPpjLZ6mVjri0V5PLZQEeo2KpE2BYKSKh7Y6Yj84tjJprosMKjL2Lt0iNvdWR4awPGb-b4fUY999N5h-JToN3TpI/s640/spdt7.png" width="640" /></a></div>
<br />
<span style="color: red; font-size: large;">SS05 Critico</span><br />
<span style="color: black;">Visualizza un elenco di feature service dove la proprietà <b><i>filter web content</i></b> è disabilitata. Disabilitando questa proprietà, consenti all'utente di inserire nei campi di input qualsiasi cosa, ciò potrebbe esporre il servizio a potenziali attacchi <a href="https://it.wikipedia.org/wiki/Cross-site_scripting" target="_blank">XSS</a>. Questa proprietà è abilitata in modo predefinito e, a meno di entità o attributi HTML richiesti, non deve essere abilitata. <a href="http://server.arcgis.com/en/server/latest/publish-services/linux/feature-services-and-client-applications.htm#ESRI_SECTION1_CE856452327D42ED95044D9EC32E4598" target="_blank">Qui</a> potete vedere la lista delle entità e attributi HTML supportati.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEievqCCeOyDduTyF9WTUO7xpM-1qC2DYQ002go-CDDwKAIcnCgJxWJNzxKlZhcQDT4GkOxD2B_46vvHsesCcfrlUpQTC4DC0uiyqntPxomNf1_8mOj5y98IDP-y6XWS4ebqx_OIZX_zAmR6/s1600/spdt9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEievqCCeOyDduTyF9WTUO7xpM-1qC2DYQ002go-CDDwKAIcnCgJxWJNzxKlZhcQDT4GkOxD2B_46vvHsesCcfrlUpQTC4DC0uiyqntPxomNf1_8mOj5y98IDP-y6XWS4ebqx_OIZX_zAmR6/s640/spdt9.png" width="636" /></a></div>
<br />
<br />
<span style="color: red; font-size: large;">SS06 Critico</span><br />
Controlla se i permessi non predefiniti sono applicati alla cartella System nel Server Manager.<br />
L'impostazione predefinita consente solo agli amministratori e ai pubblicatori di avere accesso ai servizi contenuti nella cartella System.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTsXJf0TtrrbAMME_S755iRu6B0EPKoI2khviDjRH71jJwtfLX7oX3r3sElAPNbg5AvQiImO9kryLGBLYgvPgazjoZIML7Urd9hybzSy0otK6-oyg-B3xggHddH6-ammvkyLaGREE4Wgvy/s1600/spdt10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="430" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTsXJf0TtrrbAMME_S755iRu6B0EPKoI2khviDjRH71jJwtfLX7oX3r3sElAPNbg5AvQiImO9kryLGBLYgvPgazjoZIML7Urd9hybzSy0otK6-oyg-B3xggHddH6-ammvkyLaGREE4Wgvy/s640/spdt10.png" width="640" /></a></div>
<br />
<br />
<span style="color: orange; font-size: large;">SS07 Importante</span><br />
<span style="color: black;">Controlla se la directory dei servizi REST è accessibile attraverso un web browser. A meno che non venga utilizzata attivamente per cercare e trovare servizi da parte degli utenti, dovrebbe essere disattivata per ridurre la possibilità che i servizi possano essere visualizzati, trovati tramite una ricerca su web o interrogati tramite i moduli HTML. Inoltre<span lang="it"> fornisce un'ulteriore protezione contro attacchi <a href="https://it.wikipedia.org/wiki/Cross-site_scripting" target="_blank">XSS</a>. In <i>system->handlers->rest->servicesdirectory->edit</i> può essere disabilitata.</span></span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinys1-Nw4f3Zw_PjdDZYUNd5jaq6MgouQGcIpUKvZ0BdhgX-AwvaJP_WnDF5zEr3d9W_nrpElrJerbHyEhvV-pYDGfPylQLIX4hM2a2LAeoXCTVXJlcTNF-lffnhCJyjUivjoP7O8dElsw/s1600/spdt11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="530" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinys1-Nw4f3Zw_PjdDZYUNd5jaq6MgouQGcIpUKvZ0BdhgX-AwvaJP_WnDF5zEr3d9W_nrpElrJerbHyEhvV-pYDGfPylQLIX4hM2a2LAeoXCTVXJlcTNF-lffnhCJyjUivjoP7O8dElsw/s640/spdt11.png" width="640" /></a></div>
<br />
<span style="color: orange; font-size: large;">SS08 Importante</span><br />
Controlla se le richieste cross - domain sono limitate a specifici domini. Per ridurre la possibilità che applicazioni sconosciute inviino comandi malevoli ai tuoi servizi web, una best practice è limitare l'utilizzo dei tuoi servizi web alle applicazioni ospitate solo ai domini sicuri. Pertanto in <i>system->handlers->rest->servicesdirectory->edit </i>è possibile impostare nella casella <b>AllowedOrigins</b> al posto dell'asterisco la lista dei domini consentiti separati da una virgola (es: http://host.arcgis.com, https://gisserver.example.com)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy1VBOhodoaHfM6mGQ9VyCW9WGMTIiTQPbClmcExu4uIPLvpWBgfiARBn6Y6-U2Sn9IOAtr3IpiAes6BzYq8OQ6ecXayixhD_2ImbNCs_S0poJ8ly071dFKUAfCO7HUh8aTGaxiUrFkhSx/s1600/spdt12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="528" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy1VBOhodoaHfM6mGQ9VyCW9WGMTIiTQPbClmcExu4uIPLvpWBgfiARBn6Y6-U2Sn9IOAtr3IpiAes6BzYq8OQ6ecXayixhD_2ImbNCs_S0poJ8ly071dFKUAfCO7HUh8aTGaxiUrFkhSx/s640/spdt12.png" width="640" /></a></div>
<br />
<span style="color: orange; font-size: large;">SS09 Importante</span><br />
<span style="color: black;">Visualizza una lista di servizi dove il database può essere accessibile via workspace dinamici.</span><br />
<span style="color: black;">Abilitare il servizio ai workspace dinamici deve essere adeguatamente salvaguardato per evitare che accessi di terze parti possano creare dei danni alla banca dati connettendosi via rest. Pertanto la funzionalità deve essere abilitata solo se realmente necessaria all'applicazione web. In quest'ultimo caso occorrerà connettersi al database dando solo i privilegi minimi di sola lettura alle tabelle strettamente necessarie.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimlATFKjSjtEbPUM6AhLEXvCUXtVE-mRhNlvOSo8TXeWZEHXcpg54C6Mq_DIC2OgWAUCrs6QaZK2YWN83iWwuoCjs0-FFxtoVqc1InnTiPaotAngTzwlFizVOtV4WY4ZDpsdnx5Q239IRD/s1600/SPDT13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="498" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimlATFKjSjtEbPUM6AhLEXvCUXtVE-mRhNlvOSo8TXeWZEHXcpg54C6Mq_DIC2OgWAUCrs6QaZK2YWN83iWwuoCjs0-FFxtoVqc1InnTiPaotAngTzwlFizVOtV4WY4ZDpsdnx5Q239IRD/s640/SPDT13.png" width="640" /></a></div>
<br />
<span style="color: #bf9000; font-size: large;">SS10 Raccomandato</span><br />
Verifica se uno o più web adaptor sono registrati su HTTPS. Per consentire al Server Manager di reindirizzare in https, tutti i web adaptor dovrebbero essere registrati su HTTPS.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfed4sB8U-1Lg16joZl2qB6qSFULQNg1Fb0epw3a6iQoZaK4Cp_xkgA05MLYOrUTRH0WlmjRvQ2SN2aS_M_F_gxGExaf0th4ehkBXGDpMHht3np8e3caqvPWXqr5iYFcPY5qd8hAVxWJcl/s1600/SPDT14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="484" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfed4sB8U-1Lg16joZl2qB6qSFULQNg1Fb0epw3a6iQoZaK4Cp_xkgA05MLYOrUTRH0WlmjRvQ2SN2aS_M_F_gxGExaf0th4ehkBXGDpMHht3np8e3caqvPWXqr5iYFcPY5qd8hAVxWJcl/s640/SPDT14.png" width="640" /></a></div>
<span style="color: #bf9000; font-size: large;">SS11 Raccomandato</span><br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Verifica se l'account del PSA è abilitato. E' consigliato disabilitare questo account per assicurarsi che non ci sia altro modo di amministrare ArcGIS Server se non tramite i gruppi o i ruoli specificato nell'identity store. In <i>security->psa </i>è possibile disabilitare l'account PSA.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<img border="0" height="388" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhynMXm9CxRGKWBf8nE8Ez87AEwYC-JaG72faO8Nf5Rf6UoKrlrakouLCc9msqFwfcz-o3miOslL-lC6rrtkxg57rxyJAHBmhawShBIgz4Af_QPee5ooq06Lve-B4oRifCVyYq1dZn45zcj/s640/SPDT15.png" width="640" /><br />
<div class="separator" style="clear: both; text-align: left;">
<span style="color: #bf9000; font-size: large;">SS12 Raccomandato</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: black;">Visualizza una lista di servizi feature che ha le operazioni di <b>update</b> e <b>delete</b> abilitate e <u><span style="color: red;">non sono protetti</span></u>. </span></div>
<span style="color: black;"></span><br />
<div class="separator" style="clear: both; text-align: center;">
<span style="color: black;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMQyeW9ib7MaHkrBLNlIbgLtXJit7vld6jrbS-_WhLmCEtls3SCzNJPG0XciwR1ka7gUZTPDQhxllQhLM-ImNBbfyigMpH9jX1erXLfixahSZMMe5HNRkaRgFanIlbQMl5PZzFRMaBM_3C/s1600/untitled.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMQyeW9ib7MaHkrBLNlIbgLtXJit7vld6jrbS-_WhLmCEtls3SCzNJPG0XciwR1ka7gUZTPDQhxllQhLM-ImNBbfyigMpH9jX1erXLfixahSZMMe5HNRkaRgFanIlbQMl5PZzFRMaBM_3C/s200/untitled.png" width="200" /></a></span></div>
<span style="color: black;">
</span>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="color: black;">Questo consente che i dati possano essere modificati o cancellati senza autenticazione.</span></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif42sROJX1IQDgNCReL5DxZew5Ab0Km17GCl3ry3rhaKMkYlcttIGX1wlop02pzJBUe-eUSHfdGy2ft-0woS93ceRdvySDNCAA8VH9f_mvWymimg-zhIm6ueXOiQUhMYRzs0RGUmD5EzCT/s1600/SPDT16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="376" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif42sROJX1IQDgNCReL5DxZew5Ab0Km17GCl3ry3rhaKMkYlcttIGX1wlop02pzJBUe-eUSHfdGy2ft-0woS93ceRdvySDNCAA8VH9f_mvWymimg-zhIm6ueXOiQUhMYRzs0RGUmD5EzCT/s640/SPDT16.png" width="640" /></a></div>
<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-83237672095001322852015-10-10T11:58:00.003+02:002015-10-10T11:58:37.011+02:00ArcGIS Pro: Nun te regghe Queued(Task)ArcGIS Pro si differenzia nettamente dalle applicazioni ArcGIS desktop esistenti, poichè è sviluppato secondo un'architettura multithread per sfruttare le moderne CPU/GPU con più core di esecuzione. Per lo sviluppatore di add-in che vuole estendere le funzionalità di ArcGIS Pro, questo significa modificare il modello di programmazione e familiarizzare, in un primo momento, con alcuni nuovi concetti che possono apparire bizzarri. Ovviamente, come con qualsiasi novità, lavorare con questi modelli diventerà gradualmente sempre più facile, ed i benefici del multithreading saranno sempre più evidenti.<br />
Sfide che affronterai nella programmazione multithreading:<br />
Le seguenti quattro differenze fondamentali distinguono le applicazioni multithread tra cui ArcGIS Pro, da una classica applicazione a singolo thread singolo:<br />
<ul>
<li>Per garantire un’esperienza d’uso (<a href="https://it.wikipedia.org/wiki/User_Experience" target="_blank">UX</a>) responsiva, il thread dell'interfaccia grafica utente (GUI) deve essere in grado di ricevere l'input da parte dell'utente e produrre output senza intoppi e senza interruzioni. Ciò significa che le esecuzioni delle azioni programmate devono essere eseguite in modo asincrono su thread di lavoro separati; il thread della GUI non dovrebbe mai svolgere un lavoro di qualsiasi tipo che blocchi nell’attesa. Ciò è in contrasto con le esistenti applicazioni ArcGIS desktop dove la maggior parte del lavoro viene eseguito direttamente sul singolo thread della GUI.</li>
<li>Mentre il lavoro è in esecuzione sui thread in background, agli utenti deve essere presentata un’interfaccia utente logicamente coerente e informativa. Comandi, strumenti, e altre parti dell'interfaccia utente devono essere attivate o disattivate opportunamente basandosi su quali operazioni sono in esecuzione, e dovrebbe essere fornito un adeguato feedback. Se un'operazione di lunga esecuzione è logicamente annullabile, dovrebbe essere fornita la possibilità di annullarla.</li>
<li>Operazioni che possono generare conflitto non dovrebbero essere eseguite simultaneamente e devono sempre essere eseguite in una sequenza logica appropriata. Ad esempio, le operazioni su una mappa non possono essere eseguite mentre il progetto che contiene la mappa è ancora in fase di caricamento ed un insieme di feature selezionate non può essere cancellato finché la selezione stessa non è stata completata. La maggior parte delle operazioni avviate tramite l'interazione dell'utente sono logicamente dipendenti dall’ordine e dovrebbero essere eseguite in serie.</li>
<li>Bisogna fare attenzione a garantire che l'accesso allo stato volatile, cioè l'accesso alle variabili all'interno del programma, sia correttamente sincronizzato quando tale stato è condiviso tra i thread. Ad esempio, se un oggetto collection è condiviso tra un thread di lavoro e il thread della GUI, entrambi i thread devono essere coordinati per l’accesso alla collection in modo che un thread non legga gli elementi della collection, mentre un altro thread simultaneamente sta aggiungendo o rimuovendo elementi. Questo tipo di protezione è comune a tutti i tipi di programmazione multithreaded e viene normalmente realizzato utilizzando un lock. In un'applicazione in cui più parti indipendenti possono estendere il comportamento dell'applicazione, le operazioni di coordinamento possono diventare complesse e fuori controllo senza un comune framework che orchestra i vari componenti a lavorare insieme.</li>
</ul>
<h3>
<br />Il modello di threading interno ad ArcGIS Pro</h3>
Gli ingegneri di Esri hanno posto la massima priorità per rendere ArcGIS Pro facile da programmare il più possibile nella nuova architettura multithread. A tal fine, ArcGIS Pro incorpora le più recenti funzionalità della programmazione asincrona fornita da Microsoft insieme a nuove infrastrutture threading specifiche dell'applicazione su misura per ridurre la complessità del codice.<br />
Nella maggior parte dei casi, gli sviluppatori di add-in dovrebbero solo aver bisogno di trattare con due thread: il thread dell'interfaccia utente e un thread di lavoro specializzato forniti dall'applicazione.<br />
Internamente, ArcGIS Pro utilizza un gran numero di thread per vari scopi, tra cui la rasterizzazione, il rendering dei grafici, il caricamento dei dati e la selezione degli algoritmi di geoprocessing che sfruttano il parallelismo per velocizzare il calcolo. Mantenere tutte queste attività senza blocchi e senza conflitti richiede una notevole attività di coordinamento e di complessità associata; per questo motivo, questi thread sono completamente interni e isolati agli sviluppatori nell'ambito delle implementazioni con l’SDK pubblico. Quando viene chiamato un metodo nella API pubblica, l'implementazione interna può, quando applicabile, dividere l’operazione e delegare parti ad uno o più di questi thread interni specializzati, o accodare le operazioni che alla fine vengono eseguite all'interno di un processo esterno o un servizio web .<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSr2-6ZwdinfyJaudFUlwx7hCR0-Dyh2GF94xcKYuv9aFRSCEAncs__p4N1yEtRrQBO9IsCWJB2hQb_8LOuWXLmXi6oXogw4EsBSFBdScPF1I5AOfZxDCUEtkbI5JRRMXkAfSf2gpvW6EX/s1600/mtarcgispro1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSr2-6ZwdinfyJaudFUlwx7hCR0-Dyh2GF94xcKYuv9aFRSCEAncs__p4N1yEtRrQBO9IsCWJB2hQb_8LOuWXLmXi6oXogw4EsBSFBdScPF1I5AOfZxDCUEtkbI5JRRMXkAfSf2gpvW6EX/s640/mtarcgispro1.png" width="640" /></a></div>
<br />
<h3>
<br />Attività (Tasks) e il modello asincrono basato su attività (TAP)</h3>
I metodi all'interno ArcGIS Pro SDK rientrano in tre categorie:<br />
- Metodi asincroni che possono essere chiamati in qualsiasi thread. Metodi di questo tipo sono nominati utilizzando il suffisso Async e di solito restituiscono Tasks. In alcuni casi, può essere fornita sia la versione sincrona che asincrona del metodo.<br />
- Metodi sincroni che dovrebbero essere chiamati solo sul thread di lavoro. Metodi di questo tipo sono segnalati nella guida in linea delle API e un tip sul codice appariranno quando siamo col cursore sul metodo.<br />
- Metodi sincroni che dovrebbero essere chiamati solo sul thread della GUI. Questi tipi di metodi sono di solito associati con WPF.<br />
Se un metodo su un particolare oggetto viene chiamato sul thread sbagliato, la chiamata genera un'eccezione di tipo <strong>ArcGIS.Core.CalledOnWrongThreadException</strong>. Se non sei sicuro su un particolare caso, è possibile consultare la guida del componente SDK o l’help fornito da Microsoft per determinare se un particolare metodo o una proprietà ha delle restrizioni.<br />
All'interno dell’SDK - in particolare all'interno del namespace ArcGIS.Core – il thread di lavoro associa metodi e proprietà che tendono ad essere a grana fine. Per ridurre il tempo associato con la schedulazione e la commutazione di contesto, questi metodi sono sincroni e devono essere utilizzati nel codice usando task.<br />
Il .NET Task Parallel Library di Microsoft (TPL) e il modello di programmazione associata noto come il modello asincrono basato su attività (TAP) semplificano la creazione di codice asincrono all'interno di un'applicazione multithread. La classe Task viene utilizzata per rappresentare un'operazione eseguita in modo asincrono.<br />
Nel seguente esempio, il metodo PrintReportAsync viene richiamato e restituisce immediatamente un oggetto Task al chiamante. Nel frattempo, la funzione di stampa continua l’esecuzione in background su un altro thread.<br />
<br />
private void Button_Click(object sender, RoutedEventArgs e)<br />
{<br />
Task t = PrintReportAsync ("HP1");<br />
// Attendo che il task abbia finito.<br />
t.Wait ();<br />
MessageBox.Show ("Il Report è pronto!");<br />
}<br />
<br />
Questo esempio vuole mostrare un messaggio quando la stampa è completata e utilizza il metodo Wait sull'oggetto Task restituito per sospendere il thread chiamante fino a quando il task ha completato il suo compito. <br />
Questo approccio presenta due grandi inconvenienti: in primo luogo il thread chiamante non può fare altro mentre è in attesa; in realtà è meno efficiente che semplicemente chiamare una versione sincrona della funzione di stampa. In secondo luogo, poiché il thread chiamante è un thread della GUI, l'interfaccia utente risulta ‘congelata’. Un thread sospeso, ovviamente, non è in grado di elaborare l'input dell'utente, aggiornare elementi grafici o fare qualsiasi altra cosa. Per queste ragioni, non si dovrebbe mai usare il metodo Wait su un thread della GUI.<br />
Fortunatamente, .NET introduce le funzionalità al linguaggio <strong>async</strong> e <strong>await</strong>. Il modificatore <strong>async</strong> segna il metodo in modo che il compilatore sappia che il metodo è asincrono e usi l'operatore <strong>await</strong>. L'operatore <strong>await</strong> è molto utile in quanto è utilizzato per chiamare i metodi in modo asincrono e dopo per forzare il thread chiamante a tornare automaticamente alla riga successiva e continuare l'esecuzione una volta che l'operazione asincrona è stata completata. Il thread chiamante - normalmente il thread della GUI - non è bloccato ed è libero di adottare altre azioni mentre il task sul thread di lavoro è ancora in esecuzione.<br />
Si noti che possiamo modificare ora l'obiettivo originale con poche variazioni, ma in questo caso l'interfaccia utente non si blocca.<br />
<br />
private async void Button_Click(object sender, RoutedEventArgs e)<br />
{<br />
Task t = PrintReportAsync ("HP1");<br />
// Attendere (senza blocco) fino a quando il task è completato.<br />
await t;<br />
// riparte da qui quando il task è completato.<br />
MessageBox.Show ("Il report è pronto!");<br />
}<br />
<br />
<h3>
L’utilizzo di Run</h3>
Quando una funzione asincrona non è disponibile, è possibile scrivere facilmente le proprie funzioni wrapper che eseguono internamente uno o più metodi sincroni. L'esempio seguente utilizza il metodo statico <strong>Run</strong> per accodare l'esecuzione della funzione WorkFunc ad una thread casuale nel pool di thread dei Task. Si noti che il metodo click restituisce immediatamente il controllo al chiamante, mentre il WorkFunc continua a eseguire sul thread di lavoro.<br />
<br />
private void Button_Click(object sender, RoutedEventArgs e)<br />
{<br />
Task t = Task.Run ((Azione) WorkFunc);<br />
}<br />
private void WorkFunc ()<br />
{<br />
// my work<br />
}<br />
<br />
Invece di utilizzare una funzione separata, può essere impiegata una funzione anonima chiamata anche lambda. Utilizzando le lambda, mantieniamo il codice della funzione di lavoro nella funzione stessa consentendoci di utilizzare gli argomenti e le variabili locali all'interno della lambda come se fossero parte della funzione stessa.<br />
<br />
private void Button_Click(object sender, RoutedEventArgs e)<br />
{<br />
int steps = GetSteps();<br />
Task t = Task.Run (() =><br />
{<br />
// Posso utilizzare la variabile steps qui anche se mi trovo in una<br />
// diversa funzione in esecuzione su un diverso thread!<br />
// my work<br />
});<br />
}<br />
<br />
I Task possono anche essere parametrizzati per restituire un tipo particolare, come risultato di un calcolo della lambda.<br />
<br />
Task<double> t = Task.Run<double>(() =><br />
{<br />
double risultato;<br />
// Calcolo della variabile risultato …<br />
return risultato;<br />
});<br />
<br />
L'operatore <strong>await</strong> può essere utilizzato anche in linea per ottenere il risultato della funzione asincrona e senza doverlo estrarre dal Task restituito.<br />
<br />
private async void Button_Click(object sender, RoutedEventArgs e)<br />
{<br />
double computedValue = await Task.Run <double>(() =><br />
{<br />
double risultato;<br />
// Calcolo della variabile risultato ...<br />
return risultato;<br />
});<br />
// L’esecuzione riprende automaticamente qui quando il task sopra ha completato!<br />
MessageBox.Show (String.Format ("Il risultato era {0}", computedValue.ToString ()));<br />
}<br />
<br />
C'è un piccolo ‘carico’ associato ad <strong>await</strong>, quindi è sempre più efficiente chiamare più metodi sincroni all'interno della propria lambda che chiamare molte funzioni asincrone utilizzando <strong>await</strong>. Questo è particolarmente vero quando si scrive codice in un loop, dove il costo di utilizzo <strong>await</strong> attraverso centinaia o migliaia di iterazioni diventa sostanziale.<br />
<h3>
<br />L’utilizzo di QueuedTask</h3>
Mentre i Task sono un appuntamento fisso all'interno di qualsiasi codice dell’add-in, i task devono essere forniti in ArcGIS Pro in modo diverso dal tradizionale TAP. Il framework fornisce una schedulazione personalizzata del Task che dovrebbe essere utilizzato quando fornisci Task che effettuano chiamate ai metodi sincroni di ArcGIS Pro SDK. Invece di chiamare Task.Run, gli sviluppatori di add-in devono chiamare QueuedTask.Run.<br />
<br />
Task t = QueuedTask.Run (() =><br />
{<br />
// Chiama metodi SDK sincroni<br />
});<br />
<br />
La classe QueuedTask viene utilizzata al posto della classe Task per i seguenti motivi:<br />
<h4>
Controllo della concorrenza e delle code</h4>
Quando i Task vengono inviati utilizzando Task.Run, il Task associato sarà in esecuzione su un thread a caso nel pool di thread gestito ogni volta che viene chiamato. Se una chiamata successiva a Task.Run viene fatta da qualsiasi altra parte dell'applicazione, il nuovo Task inizierà a funzionare immediatamente su un altro thread mentre il primo Task è ancora in esecuzione sul primo thread. Tornando alla lista delle sfide da affrontare nel codice multithread, dovrebbe essere ovvio che l'esecuzione delle operazioni non organizzate e concorrenti rischia di far andare in crash l’applicazione o di corrompere lo stato dell'applicazione. Il comportamento di accodamento QueuedTask.Run garantisce il corretto ordine delle chiamate e riduce il rischio di conflitti. Ricordate che il parallelismo all'interno di ArcGIS Pro si realizza internamente; questo semplifica il modello di programmazione pubblica e riduce notevolmente la probabilità di conflitti.<br />
<h4>
Affinità e stato</h4>
Per motivi di prestazioni, ArcGIS Pro mantiene un notevole stato su specifici thread e, in molti casi, utilizza oggetti che hanno affinità di thread. Affinità di thread significa che un oggetto è legato ad un particolare thread e non deve interagire con qualsiasi thread ma con il thread col quale ha affinità. Vincoli di affinità sono comuni in sistemi operativi e componenti, tra cui connessioni a database, windows, controlli, code di input, timer, WPF Bitmap e server COM. In WPF, per esempio, chiamate a metodi su un qualsiasi oggetto derivato dalla classe WPF <strong>DependencyObject</strong> si tradurrà in un'eccezione se la chiamata viene effettuata da un thread da dove l'oggetto non è stato creato.<br />
Thread nel pool di thread gestiti sono anche incompatibili con la maggior parte dei componenti COM, per cui non si dovrebbe tentare di utilizzare Task.Run con codice che potrebbe eseguire direttamente o indirettamente, componenti COM.<br />
<h4>
Integrazione dell’applicazione</h4>
Quando i Task vengono eseguiti utilizzando <strong>QueuedTask.Run</strong>, essi vengono integrati automaticamente con varie funzionalità all'interno dell'applicazione come segue:<br />
<ul>
<li>L’estensione della Progress/Cancellation del framework, in cui la progress include la finestra di dialogo con lo stato di avanzamento programmabile, viene visualizzata e nascosta automaticamente e lo stato cancellazione è correttamente comunicato tra le parti interessate dell’applicazione.</li>
<li>Lo stato occupato del sistema dell’applicazione dove gli elementi dell'interfaccia utente come pulsanti e strumenti sono attivati e disattivati automaticamente quando i Task sono in esecuzione. Esecuzione dei task possono essere coordinati anche con fasi critiche quali la creazione di viste e chiusura dell'applicazione.</li>
<li>La coda dei Task è scritta nelle strutture di diagnostica del framework, quando abilitate. Questo consente agli sviluppatori di monitorare la sequenza di esecuzione dei task, i task in esecuzione e la durata dell'esecuzione. Questo tipo di informazione è preziosa per il debugging e l'analisi delle prestazioni.</li>
</ul>
<h4>
Casi in cui è accettabile l'utilizzo di Task.Run</h4>
Ci sono casi in cui l'uso di Task.Run è accettabile, ad esempio quando si eseguono operazioni in background indipendenti costituite interamente da codice in modo gestito a condizione che i particolari componenti gestiti in uso non abbiano affinità di thread. Lo sviluppatore si assume la piena responsabilità della gestione della cancellazione, della visualizzazione dello stato di avanzamento, dell'abilitazione/disabilitazione dell'interfaccia utente in modo appropriato e del coordinamento delle operazioni e della gestione della logica dei conflitti.<br />
<h3>
Progress e cancellation</h3>
I metodi asincroni possono talvolta accettare un argomento Progressor, un oggetto che viene utilizzato dal chiamante per configurare le impostazioni della finestra di dialogo per lo stato di avanzamento e annullamento e di coordinare la comunicazione tra il chiamante e il chiamato. I metodi asincroni che non sono annullabili prendono una classe Progressor, mentre i metodi annullabili prendono una classe CancelableProgressor.<br />
Gli oggetti Progressor seguono il modello stabilito dal CancelationToken di Microsoft e non possono essere creati direttamente; invece, lo sviluppatore deve creare un ProgressorSource o CancelableProgressorSource.<br />
Gli oggetti "source" consentono di configurare come il progressor gestirà il progress senza esporre queste impostazioni al codice esterno, che potrebbero accedere al Progressor. L'oggetto ProgressorSource espone i seguenti costruttori:<br />
<br />
public ProgressorSource (Action<Progressor> callback)<br />
public ProgressorSource (ProgressDialog progDlg)<br />
public ProgressorSource (string message, bool delayedShow = false)<br />
<br />
Il primo override prende un delegato che sarà chiamato, a intervalli regolari, mentre il Task è in esecuzione. Questa opzione è appropriata quando si desidera fornire un feedback specializzato durante l'esecuzione del Task.<br />
Il secondo override prende una finestra dialogo di avanzamento, oggetto costruito separatamente. Se non è già visualizzato, il progressor mostrerà automaticamente questa finestra di dialogo di avanzamento quando il Task inizia l’esecuzione e si nasconderà automaticamente al completamento del Task. Se la finestra di dialogo è già visibile, il progressor aggiornerà il contenuto della finestra di dialogo durante l'esecuzione e sarà compito dello sviluppatore nascondere la finestra di dialogo di avanzamento al momento opportuno. Questa opzione è appropriata quando si desidera controllare manualmente la visibilità della finestra dello stato di avanzamento, ad esempio quando è necessario mantenere la finestra dello stato di avanzamento tra diverse attività separate.<br />
Il terzo override creerà automaticamente e mostrerà una finestra di dialogo di avanzamento quando il Task inizia l'esecuzione e lo nasconde al termine del completamento del Task. Il parametro delayedShow controlla se la finestra di dialogo di avanzamento deve essere mostrata immediatamente o ritardare la sua apparizione per consentire operazioni rapide da completare ed evitare di apparire, se non necessario. Se si prevede che il Task sia rapido nel completamento dell’esecuzione, impostare questo parametro a true. Se si prevede che il Task abbia bisogno di più di uno o due secondi per completare l’operazione, impostare delayedShow a false in modo che la finestra di dialogo di avanzamento appaia immediatamente per trasmettere responsività.<br />
CancelableProgressors richiedono un ulteriore argomento che specifica cosa dovrebbe visualizzare il messaggio di annullamento. Verrà visualizzato il messaggio di annullamento, non appena l'utente fa clic sul pulsante Annulla nella finestra di dialogo.<br />
<br />
public CancelableProgressorSource(Action <CancelableProgressor> callback)<br />
public CancelableProgressorSource(ProgressDialog progDlg)<br />
public CancelableProgressorSource(string message, string cancelMessage, bool delayedShow = false)<br />
<br />
<h3>
Esempio di implementazione del metodo utilizzando cancellation</h3>
Lo specializzato CancelableProgressor espone una proprietà CancellationToken che può essere utilizzata per comunicare l’annullamento. All'interno dell'implementazione del metodo, il codice in esecuzione nel loop dovrebbe controllare la proprietà IsCancellationRequested e uscire dal metodo gettando l’eccezione <strong>OperationCanceledException</strong> (che riconosce la richiesta di cancellazione) come illustrato di seguito:<br />
<br />
public Task<long> CalcFactorialAsync(int x, CancelableProgressor progressor)<br />
{<br />
return QueuedTask.Run<long>(() =><br />
{<br />
long result = 1;<br />
for (int i = 1; i < x; ++i)<br />
{<br />
if (progressor.CancellationToken.IsCancellationRequested)<br />
throw new OperationCanceledException();<br />
result *= i;<br />
}<br />
return result;<br />
});<br />
}<br />
<br />
<h3>
Utilizzare con i metodi asincroni la finestra di dialogo integrata </h3>
Se il Progressor è stato configurato per mostrare lo stato di avanzamento, il Task in esecuzione può aggiornare le informazioni visualizzate nella finestra di avanzamento utilizzando il progressor (entrambe Progressor e CancelableProgressor supportano finestre di dialogo di avanzamento):<br />
<br />
public Task<long> CalcFactorialAsync(int x, Progressor progressor)<br />
{<br />
return QueuedTask.Run<long>(() =><br />
{<br />
long result = 1;<br />
for (int i = 1; i < x; ++i)<br />
{<br />
progressor.Message = string.Format("Working on step:{0}", i);<br />
result *= i;<br />
}<br />
return result;<br />
}, progressor);<br />
} <br />
<h3>
Complicazioni comuni</h3>
<h4>
Ipotesi di stato costante</h4>
Si consideri il seguente esempio. Questa chiamata viene richiamata dal thread della GUI e l'intento è quello di eliminare lo specifico layer dalla mappa della vista attiva.<br />
<br />
private Task DeleteSelectedLayerAsync(Layer layer)<br />
{<br />
return QueuedTask.Run(() =><br />
{<br />
MapView.Active.Map.RemoveLayer(layer);<br />
});<br />
} <br />
<br />
Anche se semplice in apparenza, questa funzione a volte può causare un'eccezione quando in uso all'interno dell'applicazione. L'errore qui è stato quello di pensare che lo stato del sistema rimanga statico attraverso i thread. Ci possono essere precedentemente delle operazioni in coda in esecuzione e queste devono essere completate prima che un'altra operazione possa iniziare l'esecuzione. Durante questo tempo, lo stato dell’applicazione può cambiare a causa dell’interazione con l'utente o il risultato di una operazioni ancora in esecuzione. In questo caso, l’oggetto attivo potrebbe diventare una tabella prima che la lambda effettivamente inizi l’esecuzione, nel qual caso la mappa sarà nulla determinando un'eccezione. L'approccio sicuro è quello di evitare "concatenamenti" di chiamate su variabili membro o variabili passate tra thread; utilizzare variabili locali come istantanee dello stato dell'applicazione quando il metodo è stato chiamato, dal momento che non cambieranno al loro interno.<br />
<br />
private Task DeleteSelectedLayerAsync (Layer layer)<br />
{<br />
// Prendere una "istantanea" della mappa sulla vista attiva.<br />
Map m = MapView.Active.Map;<br />
return QueuedTask.Run (() =><br />
{<br />
m.RemoveLayer(layer);<br />
});<br />
}<br />
<br />
In un ambiente multithreading si dovrebbe gestire il codice allestendo una strategia difensiva. Si consideri un Task che modifica come un particolare layer debba essere simboleggiato. Se tale Task finisce in una coda dietro un altro Task che rimuove questo stesso layer dalla mappa, la seconda operazione è logicamente invalidata dalla prima. Per gestire questo caso correttamente, il secondo Task dovrebbe essere gestito per visualizzare un avviso o annullare l'operazione in modalità silente quando viene a sapere che il layer è stato eliminato.<br />
<h4>
Thread safe con associazione dati in WPF</h4>
Per impostazione predefinita, i dati di collection associati a WPF devono essere modificati sul thread dove è stata creata l’associazione al controllo WPF. Questa limitazione diventa un problema quando si desidera riempire la collection da un thread di lavoro per produrre una buona esperienza per l’utente. Ad esempio, un elenco dei risultati di ricerca che viene riempito gradualmente man mano che vengono trovate corrispondenze, senza costringere l'utente ad attendere fino a quando l'intera ricerca è completata.<br />
Per ovviare a questa limitazione, WPF fornisce una classe statica <strong>BindingOperations</strong> che permette di stabilire un'associazione tra un lock e una collection (ad esempio, ObservableCollection<T>). Tale associazione consente a collection associate di essere aggiornate dai thread esterni al thread principale della GUI, in modo coordinato senza generare la consueta eccezione.<br />
<strong>BindingOperations.EnableCollectionSynchronization(Items, _lockObj);</strong><br />
Nell'esempio sopra, la variabile _lockObj - di tipo oggetto - è in genere istanziata quando viene creata la classe contenitore e servirà come lock per il coordinamento. Una volta che si chiama <strong>EnableCollectionSynchronization</strong>, WPF entrerà nello specificato lock quando c’è lettura o scrittura alla collection associata. Come proprietari della collection, si è obbligati a inserire il lock durante la lettura alla collection o scrittura della collection.<br />
I wrapper <strong>ReadOnlyObservableCollection</strong> sono comunemente usati per forzare le sole letture semantiche sulle proprietà della collection osservabile. Per impostare correttamente la sincronizzazione con multithreading, è necessario chiamare <strong>EnableCollectionSynchronization</strong> sul wrapper, invece che sulla collection stessa, dal momento che è il wrapper al quale il WPF sarà associato effettivamente.<br />
<br />
internal class HelloWorld<br />
{<br />
private ObservableCollection<string> _items = new ObservableCollection<string>();<br />
private ReadOnlyObservableCollection<string> _itemsRO;<br />
private Object _lockObj = new Object();<br />
internal HelloWorld()<br />
{<br />
_itemsRO = new ReadOnlyObservableCollection<string>(_items);<br />
BindingOperations.EnableCollectionSynchronization(_itemsRO, _lockObj);<br />
}<br />
//la proprietà pubblica utilizzata per il binding <br />
public ReadOnlyObservableCollection<string> Items { get { return _itemsRO; } }<br />
//all’interno della funzione di lavoro, il lock è inserito prima di modificare //la collection:<br />
public void FillCollectionAsync()<br />
{<br />
QueuedTask.Run(() =><br />
{<br />
// letture e scritture dovrebbe essere fatte all’interno del lock<br />
lock (_lockObj)<br />
{<br />
_items.Add( GetData() );<br />
}<br />
});<br />
}<br />
<br />
<h4>
Oggetti "Live" come proprietà</h4>
Si deve prestare attenzione quando si espongono oggetti – soprattutto collection - come proprietà pubbliche se la collezione è destinata a cambiare in un thread separato. Se qualcuno ottiene e trattiene tale proprietà e poi inizia l'enumerazione attraverso un thread A, un'eccezione può essere generata se il proprio codice modifica la collection sul thread B in quanto non vi è alcun lock di collaborazione tra essi. Distribuire in sola lettura istantanee della collection è più sicuro.<br />
<h4>
Eseguire codice sul thread della GUI</h4>
Ci sono casi in cui di tanto in tanto, mentre il codice viene eseguito su un thread di lavoro, si incontrano situazioni in cui è necessario chiedere input da parte dell'utente prima di procedere. Non si dovrebbe cercare di presentare una finestra direttamente dal thread di lavoro poiché le finestre hanno affinità di thread. Una finestra di dialogo creata sul thread di lavoro non si collega alla coda di input del thread della GUI e non rispetta lo z-order e la politica di focus stabilita dal thread GUI. In generale, è possibile eseguire codice sul thread della GUI da un thread di lavoro usando l'oggetto dispatcher dell'applicazione.<br />
Questo può essere fatto in modo sincrono.<br />
<br />
FrameworkApplication.Current.Dispatcher.Invoke (() =><br />
{<br />
// Fare qualcosa sul thread della GUI<br />
System.Windows.MessageBox.Show ("Pronto!");<br />
});<br />
<br />
O in modo asincrono:<br />
<br />
FrameworkApplication.Current.Dispatcher.BeginInvoke (() =><br />
{<br />
// Fare qualcosa sul thread della GUI<br />
System.Windows.MessageBox.Show ("Pronto!");<br />
});<br />
<br />
Si dovrebbe cercare di raccogliere le informazioni necessarie da parte dell'utente sul thread della GUI prima di eseguire il lavoro in modo da non dover utilizzare questa scorciatoia. Bloccando chiamate tra thread c’è rischio di deadlock e di trattenere operazioni in esecuzione sul thread di lavoro.<br />
<h4>
La gestione delle eccezioni in ambiente asincrono</h4>
Come le funzioni sincrone, le funzioni asincrone possono gettare eccezioni. Questo introduce un problema interessante da quando il chiamante fornisce il try/catch in un thread, e l'eccezione viene generata su un altro. Inoltre, il frame del chiamante non è solitamente ancora nello stack quando viene generata l'eccezione.<br />
Tuttavia, .NET permette di utilizzare async/await con try/catch in modo che, se viene generata un'eccezione dal codice in esecuzione all'interno del Task, sarete in grado di catturare di nuovo da dove la funzione asincrona è stata chiamata. Si noti che la funzione asincrona deve restituire Task o Task<T> per eccezioni asincrone per essere adeguatamente rediretta (non void).<br />
<br />
try<br />
{<br />
var result = await PrintMapAsync ();<br />
}<br />
catch (Exception e)<br />
{<br />
// gestione eccezione.<br />
}<br />
<br />
Se viene generata un'eccezione da parte del worker e non è stato fornito un try/catch intorno a dove si attende il worker, il runtime .NET si collegherà all'eccezione come eccezione inner, <strong>UnobservedException</strong>.<br />
Eccezioni Unobserved solitamente compaiono solo quando l'oggetto eccezione viene raccolto dalla garbage collection di .NET, in nessun posto vicino a dove in realtà si è verificata l'eccezione. Se si ottiene uno di questi, esaminare l'eccezione interna per ottenere lo stack delle chiamate fallite. Nella finestra di controllo di VisualStudio, è possibile utilizzare la pseudo variabile <em>$exception</em> per esaminare il corrente oggetto eccezione.<br />
<h4>
Oggetti Freezable</h4>
WPF definisce un modello in cui determinati tipi di oggetti possono essere "congelati". Una volta che l'oggetto è congelato, modifiche non possono essere apportate all'oggetto senza che si generi un'eccezione. Oggetti freezable possono migliorare le prestazioni in alcune situazioni, e permettono anche di condividere l'oggetto tra i thread (vedi affinità di thread). Ad esempio, se un BitmapImage viene creato su un thread di lavoro, non è possibile utilizzarlo in seguito sul thread della GUI a meno di congelarlo prima.<br />
Si consideri un caso comune in cui l'associazione venga utilizzata in combinazione con le immagini che sono state generate su un thread di lavoro. La classe di esempio VM qui sotto espone una proprietà chiamata Img:<br />
<br />
public class VM: INotifyPropertyChanged<br />
{<br />
public BitmapImage Img {get {return _image; }}<br />
...<br />
}<br />
<br />
Questa proprietà restituisce un'istanza di <strong>BitmapImage</strong> (un oggetto Freezable), che è poi associata ad un pulsante in XAML:<br />
<br />
<Button><br />
<Image Source = "{Binding Img}"> </ Immagine><br />
</ Button><br />
<br />
La bitmap sottostante viene periodicamente aggiornata sul thread di lavoro come segue; notare che verrà creata la bitmap sul thread di lavoro:<br />
<br />
public Task Refresh ()<br />
{<br />
return QueuedTask.Run (() =><br />
{<br />
var uri = GenerateThumbnail();<br />
Img = new BitmapImage (uri);<br />
});<br />
}<br />
<br />
Nel processo di rendering dell'interfaccia utente, WPF tenterà di accedere alla proprietà bitmap dal thread della GUI ... ma questo si tradurrà in un'eccezione perché la bitmap è ancora "scongelata" e quindi ancorata al suo thread di lavoro principale. Questo problema può essere risolto semplicemente "congelando" la Bitmap dopo il suo l'aggiornamento.<br />
<br />
var uri = GenerateThumbnail ();<br />
Img = new BitmapImage (uri);<br />
Img.Freeze ();<br />
<br />
Nota: non tutte le classi che ereditano da <strong>System.Windows.Freezable</strong> possono essere congelate. Utilizzare la proprietà <em>CanFreeze</em> per verificare se l’oggetto può essere congelato.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-30594453847496117312015-05-11T16:32:00.000+02:002015-05-12T15:31:58.071+02:00Tutti pazzi per il SOIUna delle novità più interessanti introdotte in ArcGIS Server 10.3.1 è il SOI ovvero Server Object Interceptor. Come si può un po' dedurre dal nome, un SOI intercetta le chiamate REST, SOAP e di servizi OGC su servizi di tipo Map o Image prima e dopo l'esecuzione di una operazione su una SOE (Server Object Extension) o sul SO (Server Object). In pratica i SOI estendono le capability dei servizi GIS (map e image) esistenti, modificando, bloccando o inoltrando le richieste REST/SOAP e OGC ma, a differenza di una SOE, le API rimangono inalterate mentre il comportamento può cambiare: non verranno quindi creati nuovi web service end point mentre, come avviene per le SOE, possono essere sviluppate in NET o Java e distribuite dagli administrator e publisher dal manager.<br />
Giusto per fare un paragone, i SOI possiamo pensarli come le <a href="http://www.oracle.com/technetwork/java/filters-137243.html" target="_blank">server filter</a>.<br />
<br />
Ma come mai sono stati introdotti i SOI? Precedentemente non era possibile modificare il comportamento delle chiamate standard dei servizi GIS e alcune funzionalità personalizzate erano piuttosto complicate e richiedevano l'utilizzo di proxy - comunque non erano soluzioni perfettamente integrate nei servizi GIS.<br />
I potenziali use case per lo sviluppo di SOI sono:<br />
<br />
<strong>Sicurezza</strong><br />
<ul>
<li>controllo di accesso a livello di layer e di operation</li>
<li>extent/AOI basato su masking</li>
<li>risposte di query modificate/perfezionate sia negli attributi che nella geometria</li>
<li><a href="http://it.wikipedia.org/wiki/Watermark_(informatica)" target="_blank">watermark</a>, classificazioni e personalizzazioni</li>
<li>auditing e logging</li>
</ul>
<strong>Integrazione sistemi e dati</strong><br />
<ul>
<li>integrazione con dati esterni e propri sistemi</li>
<li>validazione degli input e output (post processing)</li>
<li>inserimenti avanzati (in input e output), funzionalità personalizzate (reindirizzare specifiche operazioni ad entità esterne)</li>
</ul>
<br />
<div>
I servizi di tipo Map e Image, con incluse le capability (ad esempio i feature servizi) supportano tre diversi tipi di richieste:</div>
<ul>
<li>richieste REST API</li>
<li>richieste SOAP API</li>
<li>richieste OGC</li>
</ul>
<br />
Come possiamo vedere dalle immagini il SOI si frappone tra i client e SO/SOE<br />
I client fanno delle richieste che possono essere gestite o meno sia prima di inviarle all'handler responsabile che dopo l'elaborazione (ma prima di inviarle al client).<br />
<br />
Qui la risposta post process può anche essere reindirizzata altrove oltre che al client <br />
<div>
<div align="justify" class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihWGkG2VH7_UGST5vN9GUO5DcRwsSPaE4kMmjRdcNcnPjN9jlGMGSC0Bb4Dq0HTYUe9ef-rzlOFc0jpb0UsJ-kAAjQ89uoAdY5KPCu69yRMsMm-7Qp2xBb3926EThsnvkyu6KF9LYlslvY/s1600/xBlog4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="337" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihWGkG2VH7_UGST5vN9GUO5DcRwsSPaE4kMmjRdcNcnPjN9jlGMGSC0Bb4Dq0HTYUe9ef-rzlOFc0jpb0UsJ-kAAjQ89uoAdY5KPCu69yRMsMm-7Qp2xBb3926EThsnvkyu6KF9LYlslvY/s640/xBlog4.PNG" width="640" /></a></div>
<br />
Qui la richiesta può essere sempre inviata altrove oltre che agli oggetti sottostanti al servizio<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZkIJZqvrS72ffl-9P8mNjZl-nZdrZKmQmeHsNaHH3oImtjnt2awRQwwbwz2sCu5rSR4QMPKDUf6L4uf7bFDrT9KLgaWkom_Sn3uWZ3Hx5Kj0RiQPG7gy3CeLt2FV0z2ffzggLDxbq4SpB/s1600/xBlog3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZkIJZqvrS72ffl-9P8mNjZl-nZdrZKmQmeHsNaHH3oImtjnt2awRQwwbwz2sCu5rSR4QMPKDUf6L4uf7bFDrT9KLgaWkom_Sn3uWZ3Hx5Kj0RiQPG7gy3CeLt2FV0z2ffzggLDxbq4SpB/s640/xBlog3.PNG" width="640" /></a></div>
<br />
<br />
Affinché un SOI possa intercettare queste richieste, è necessario implementare le seguenti interfacce:</div>
<div>
- <strong><em>IRESTRequestHandler</em></strong> - per la gestione delle richieste API REST</div>
<div>
- <strong><em>IRequestHandler2</em></strong> - per la gestione delle richieste SOAP API, tra le quali anche le richieste dai clienti desktop quali ArcMap</div>
<div>
- <strong><em>IWebRequestHandler</em></strong> - per la gestione delle richieste OGC</div>
<div>
<br />
Tutte queste interfacce si trovano nello spazio dei nomi <em>Esri.ArcGIS.esriSystem</em>.<br />
</div>
<div>
Anche se una configurazione del servizio non supporta le richieste OGC (ad esempio WMS, WFS ecc.), è necessario gestire tutte le interfacce di cui sopra. <br />
A seconda della logica di business che si desidera di implementare, si può scegliere tra due approcci generali. Se si implementa un SOI che gestirà funzioni di sicurezza, allora è consigliabile iniziare ad implementare tutte le interfacce e bloccare tutte le richieste. Una volta implementato il codice personalizzato, è possibile consentire l'accesso tramite le interfacce. Se non adottiamo questo metodo non bloccando tutte le richieste in arrivo e consentendo l'accesso successivamente, c'è maggiore rischio ad esporsi a 'buchi' nella sicurezza. Mentre, se non si sta sviluppando funzionalità di sicurezza, è possibile implementare le tre interfacce facendo passare tutte le richieste con l'implementazione standard di base, al fine di consentire le funzionalità già presenti e successivamente aggiungere la logica di business per una o più operazioni che si desidera modificare.</div>
<div>
<span style="color: black;">Quando un servizio GIS è stato configurato con un SOI, il server inoltra tutte le richieste del servizio al SOI. Ovviamente è responsabilità del SOI elaborare le richieste, delegare la richiesta ai correnti oggetti del servizio Map o Image, se applicabile, e poi eventuali ulteriori elaborazioni sulla risposta prima di restituirla al client.</span><br />
</div>
<div>
<em><strong>Implementare l'interfaccia IRESTRequestHandler</strong></em></div>
<div>
La gestione delle API REST è il modo più semplice per iniziare con lo sviluppo di un SOI,<span style="color: red;"> </span><span style="color: black;">dal momento che tutti i parametri e le risposte dell'operazione sono text /JSON e possono essere facilmente gestiti.</span><br />
</div>
<div>
La principale funzione di questa interfaccia è:<br />
</div>
<div>
<em><span style="color: black;">public byte [] HandleRESTRequest (string capabilities, string resourceName, string</span></em></div>
<div>
<em><span style="color: black;"> operationName, string operationInput, string outputFormat, string</span></em></div>
<div>
<em><span style="color: black;"> requestProperties, ref string responseProperties);</span></em><br />
</div>
<div>
La funzione modella le REST API in termini di risorse e di operazioni e le sue corrispondenti proprietà della richiesta. <br />
Il parametro <em>operationInput</em> contiene tipicamente un oggetto JSON che rappresenta la richiesta. Si può facilmente gestire questo oggetto utilizzando la libreria JSON disponibile nella piattaforma di vostra scelta (NET o Java). Al fine di ottenere la configurazione di default per il servizio, il REST Services Directory invoca questa operazione passando oggetti JSON vuoti per tutti gli argomenti. Delegando questa chiamata al servizio sottostante e poi manipolando l'output nel SOI, si può vedere quali risorse (layers) e operazioni (export, find, identity, ecc) vengono presentati al Services Directory e ai client.</div>
<div>
Un'altra funzione che deve essere gestita è:</div>
<div>
<em>public string getSchema ()</em></div>
<div>
Questa funzione informa il REST Services Directory su come rappresentare la configurazione del servizio. In genere, l'implementazione del SOI dovrebbe delegare questa chiamata all'oggetto sottostante del servizio di Map o Image e poi eventualmente, se lo desideri, manipolare l'output.</div>
<div>
<br />
<em><strong>Implementare l'interfaccia IRequestHandler2</strong></em></div>
<div>
L'implementazione di questa interfaccia è più complessa in quanto gestisce le richieste binarie (da ArcGIS for Desktop ed altre applicazioni basate su ArcObjects) e le richieste SOAP (da client SOAP personalizzati). In entrambi i casi, è necessario utilizzare le API ArcObjects per decodificare la richiesta in entrata, eventualmente modificare i parametri della richiesta, e quindi ricodificare la richiesta da inviare agli oggetti sottostanti dei servizi Map o Image. Anche per il post-process delle risposte, è sempre necessario utilizzare le API ArcObjects per gestire le risposte prima di inviarle al client. L'SDK contiene le classi di helper per gestire le richieste/risposte.</div>
<div>
Questa interfaccia contiene due metodi che occorre implementare:<br />
</div>
<div>
<em><span style="color: black;">public byte [] HandleBinaryRequest2 (string capabilities, byte [] request)</span></em><br />
<em></em> </div>
<div>
La funzione di cui sopra viene richiamata quando il server riceve richieste binarie (da ArcGIS for Desktop) per un servizio. Il parametro di richiesta contiene la richiesta binaria che deve essere gestita utilizzando le API ArcObjects.</div>
<div>
<em><span style="color: red;"></span></em><br />
<span style="color: red;"><em><span style="color: black;">public string HandleStringRequest (</span></em><em><span style="color: black;">string capabilities, string request</span></em></span><span style="color: black;"><em>)</em></span><br />
<em></em> </div>
<div>
Questa funzione viene richiamata quando il server riceve una richiesta SOAP (XML). I client SOAP in genere fanno queste richieste. Il parametro di richiesta contiene la richiesta XML che deve essere gestita utilizzando le API ArcObjects.<br />
</div>
<div>
<strong><em>Implementare l'interfaccia IWebRequestHandler</em></strong></div>
<div>
Richieste KML e richieste di servizi OGC (WMS e WFS) possono essere intercettate implementando l'interfaccia IWebRequestHandler nel SOI. Le funzioni in questa interfaccia rappresentano una tipica richiesta OGC che è una richiesta HTTP con query string di parametri. È necessario implementare la seguente funzione:<br />
</div>
<div>
<em><span style="color: black;">public byte [] HandleStringWebRequest (esriHttpMethod httpMethod, string requestURL,</span></em></div>
<div>
<span style="color: black;"><em> stringa queryString, string capabilities, string requestData, ref string </em><em>responseContentType, ref int respDataType)</em></span><br />
<em></em> </div>
<div>
Il parametro <em>requestData</em> è generalmente un text/XML e contiene l'input per la richiesta. Tuttavia, i parametri vengono spesso inviati tramite il parametro queryString. Il parametro respDataType informa il tuo codice su come il valore byte[] restituito deve essere interpretato.<span style="color: black;"> Se il <em>respDataType</em> indica un file, il tuo codice deve inviare i contenuti del file al percorso restituito da byte []. Il <em>responseContentType</em> informa l'handler web il tipo di contenuto da impostare mentre risponde alla richiesta HTTP.</span><br />
</div>
<div>
Una classe di helper chiamata SOISupport è parte dell' esempio <em>'Layer Access'</em> presente nell'SDK ArcObjects . Questa classe di helper contiene metodi per interagire con il servizio per delegare le richieste in arrivo, metodi per la conversione tra oggetti ArcObjects di risposta e molto altro. Inoltre nell'esempio 'Layer Access' è possibile vedere come utilizzare questi metodi in particolare quando si tratta di richieste SOAP e binarie. Altre classi nell'assembly ESRI.ArcGIS.SOESupport forniscono funzionalità per manipolare i dati e gli oggetti JSON.<br />
<br />
Ed ora passiamo alla pratica vedendo un po' di esempi.<br />
Come abbiamo accennato precedentemente lo sviluppo di un SOI è analogo a quello delle SOE.<br />
Una volta installato l'SDK ArcObjects è possibile utilizzare il template disponibile nel proprio ambiente di sviluppo.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjKHTjGLecU04B1AFR6jvFaiPmUX1y4qzajT8Miqx6rDe3wriNTbNr2a9ViW9M6fws3tBEIH34CB9Ay-itU2excRwmYUQFuej725KrYdANg6kYN0diqTE92eeh4pD1smwE50pbVDoM8g80/s1600/Cattura1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="440" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjKHTjGLecU04B1AFR6jvFaiPmUX1y4qzajT8Miqx6rDe3wriNTbNr2a9ViW9M6fws3tBEIH34CB9Ay-itU2excRwmYUQFuej725KrYdANg6kYN0diqTE92eeh4pD1smwE50pbVDoM8g80/s640/Cattura1.PNG" width="640" /></a></div>
<br />
<br />
Il template genererà il seguente codice:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> MyFirstSOI
{
[<span style="color: #2b91af;">ComVisible</span>(<span style="color: blue;">true</span>)]
[<span style="color: #2b91af;">Guid</span>(<span style="color: #a31515;">"29a910dc-1cb6-48f5-a8a5-7f723c63e553"</span>)]
[<span style="color: #2b91af;">ClassInterface</span>(<span style="color: #2b91af;">ClassInterfaceType</span>.None)]
[<span style="color: #2b91af;">ServerObjectInterceptor</span>(<span style="color: #a31515;">""</span>,<span style="color: green;">//use "MapServer" if SOI extends a Map service and "ImageServer" if it extends an Image service.</span>
Description = <span style="color: #a31515;">""</span>,
DisplayName = <span style="color: #a31515;">"SOI1"</span>,
Properties = <span style="color: #a31515;">""</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">MyFirstSOI</span> : <span style="color: #2b91af;">IServerObjectExtension</span>, <span style="color: #2b91af;">IRESTRequestHandler</span>, <span style="color: #2b91af;">IWebRequestHandler</span>, <span style="color: #2b91af;">IRequestHandler2</span>, <span style="color: #2b91af;">IRequestHandler</span>
{
<span style="color: blue;">private</span> <span style="color: blue;">string</span> _soiName;
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerObjectHelper</span> _soHelper;
<span style="color: blue;">private</span> <span style="color: #2b91af;">ServerLogger</span> _serverLog;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">String</span>, <span style="color: #2b91af;">IServerObjectExtension</span>> _extensionCache = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">String</span>, <span style="color: #2b91af;">IServerObjectExtension</span>>();
<span style="color: #2b91af;">IServerEnvironment2</span> _serverEnvironment;
<span style="color: blue;">public</span> MyFirstSOI()
{
_soiName = <span style="color: blue;">this</span>.GetType().Name;
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Init(<span style="color: #2b91af;">IServerObjectHelper</span> pSOH)
{
_soHelper = pSOH;
_serverLog = <span style="color: blue;">new</span> <span style="color: #2b91af;">ServerLogger</span>();
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Initialized "</span> + _soiName + <span style="color: #a31515;">" SOI."</span>);
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Shutdown()
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Shutting down "</span> + _soiName + <span style="color: #a31515;">" SOI."</span>);
}
<span style="color: blue;"> #region</span> REST interceptors
<span style="color: blue;">public</span> <span style="color: blue;">string</span> GetSchema()
{
<span style="color: #2b91af;">IRESTRequestHandler</span> restRequestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRESTRequestHandler</span>>();
<span style="color: blue;">if</span> (restRequestHandler == <span style="color: blue;">null</span>)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: blue;">return</span> restRequestHandler.GetSchema();
}
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleRESTRequest(<span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> resourceName, <span style="color: blue;">string</span> operationName,
<span style="color: blue;">string</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
responseProperties = <span style="color: blue;">null</span>;
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleRESTRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for handleRESTRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate REST requests here</span>
<span style="color: green;"> */</span>
<span style="color: green;">// Find the correct delegate to forward the request too</span>
<span style="color: #2b91af;">IRESTRequestHandler</span> restRequestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRESTRequestHandler</span>>();
<span style="color: blue;">if</span> (restRequestHandler == <span style="color: blue;">null</span>)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: blue;">return</span> restRequestHandler.HandleRESTRequest(
Capabilities, resourceName, operationName, operationInput,
outputFormat, requestProperties, <span style="color: blue;">out</span> responseProperties);
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> SOAP interceptors
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleStringWebRequest(<span style="color: #2b91af;">esriHttpMethod</span> httpMethod, <span style="color: blue;">string</span> requestURL,
<span style="color: blue;">string</span> queryString, <span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> requestData,
<span style="color: blue;">out</span> <span style="color: blue;">string</span> responseContentType, <span style="color: blue;">out</span> <span style="color: #2b91af;">esriWebResponseDataType</span> respDataType)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleStringWebRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleStringWebRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IWebRequestHandler</span> webRequestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IWebRequestHandler</span>>();
<span style="color: blue;">if</span> (webRequestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> webRequestHandler.HandleStringWebRequest(
httpMethod, requestURL, queryString, Capabilities, requestData, <span style="color: blue;">out</span> responseContentType, <span style="color: blue;">out</span> respDataType);
}
responseContentType = <span style="color: blue;">null</span>;
respDataType = <span style="color: #2b91af;">esriWebResponseDataType</span>.esriWRDTPayload;
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleBinaryRequest(<span style="color: blue;">ref</span> <span style="color: blue;">byte</span>[] request)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleBinaryRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleBinaryRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IRequestHandler</span> requestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> requestHandler.HandleBinaryRequest(request);
}
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleBinaryRequest2(<span style="color: blue;">string</span> Capabilities, <span style="color: blue;">ref</span> <span style="color: blue;">byte</span>[] request)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleBinaryRequest2()"</span>,
200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleBinaryRequest2"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IRequestHandler2</span> requestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler2</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> requestHandler.HandleBinaryRequest2(Capabilities, request);
}
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> HandleStringRequest(<span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> request)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleStringRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleStringRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IRequestHandler</span> requestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> requestHandler.HandleStringRequest(Capabilities, request);
}
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> Utility code
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerEnvironment2</span> ServerEnvironment
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">if</span> (_serverEnvironment == <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">UID</span> uid = <span style="color: blue;">new</span> <span style="color: #2b91af;">UIDClass</span>();
uid.Value = <span style="color: #a31515;">"{32D4C328-E473-4615-922C-63C108F55E60}"</span>;
<span style="color: green;">// CoCreate an EnvironmentManager and retrieve the IServerEnvironment</span>
<span style="color: #2b91af;">IEnvironmentManager</span> environmentManager = <span style="color: blue;">new</span> <span style="color: #2b91af;">EnvironmentManager</span>() <span style="color: blue;">as</span> <span style="color: #2b91af;">IEnvironmentManager</span>;
_serverEnvironment = environmentManager.GetEnvironment(uid) <span style="color: blue;">as</span> <span style="color: #2b91af;">IServerEnvironment2</span>;
}
<span style="color: blue;">return</span> _serverEnvironment;
}
}
<span style="color: blue;">private</span> THandlerInterface FindRequestHandlerDelegate<THandlerInterface>() <span style="color: blue;">where</span> THandlerInterface : <span style="color: blue;">class</span>
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">IPropertySet</span> props = ServerEnvironment.Properties;
<span style="color: #2b91af;">String</span> extensionName;
<span style="color: blue;">try</span>
{
extensionName = (<span style="color: #2b91af;">String</span>)props.GetProperty(<span style="color: #a31515;">"ExtensionName"</span>);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> <span style="color: green;">/*e*/</span>)
{
extensionName = <span style="color: blue;">null</span>;
}
<span style="color: blue;">if</span> (<span style="color: #2b91af;">String</span>.IsNullOrEmpty(extensionName))
{
<span style="color: blue;">return</span> (_soHelper.ServerObject <span style="color: blue;">as</span> THandlerInterface);
}
<span style="color: green;">// Get the extension reference from cache if available</span>
<span style="color: blue;">if</span> (_extensionCache.ContainsKey(extensionName))
{
<span style="color: blue;">return</span> (_extensionCache[extensionName] <span style="color: blue;">as</span> THandlerInterface);
}
<span style="color: green;">// This request is to be made on a specific extension</span>
<span style="color: green;">// so we find the extension from the extension manager</span>
<span style="color: #2b91af;">IServerObjectExtensionManager</span> extnMgr = _soHelper.ServerObject <span style="color: blue;">as</span> <span style="color: #2b91af;">IServerObjectExtensionManager</span>;
<span style="color: #2b91af;">IServerObjectExtension</span> soe = extnMgr.FindExtensionByTypeName(extensionName);
<span style="color: blue;">return</span> (soe <span style="color: blue;">as</span> THandlerInterface);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error,
_soiName + <span style="color: #a31515;">".FindRequestHandlerDelegate()"</span>, 500, e.ToString());
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;"> #endregion</span>
}
}</pre>
<br />
Come possiamo subito notare la definizione della classe è simile a quella della SOE solo che implementerà anche le interfacce <em>IWebRequestHandler</em>, <em>IRequestHandler2</em>, <em>IRequestHandler</em> ed è decorata con l'attributo ServerObjectInterceptorAttribute. <em>Init</em> e <em>Shutdown</em> sono sempre presenti visto il SOI 'vive' con il servizio GIS nel quale è abilitato.<br />
Nella region 'Utility code' sono già disponibili una funzione <em>FindRequestHandlerDelegate </em>ed una proprietà <em>ServerEnvironment </em>. <em>FindRequestHandlerDelegate </em>determina il corretto delegato per reindirizzare la richiesta in arrivo mentre la proprietà <em>ServerEnvironment </em>è utilizzata dalla funzione stessa per verificare se la richiesta è indirizzata al SO o ad una specifica SOE e quindi di conseguenza determinare il delegato corrispondente.<br />
<br />
Vediamo ora un esempio che modifica la richiesta dopo averla fatta elaborare all'oggetto sottostante al servizio. Watermark sulla mappa generata su una richiesta di Export<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Studioat.ArcGis.Soi.Rest
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Collections.Generic;
<span style="color: blue;">using</span> System.Diagnostics.CodeAnalysis;
<span style="color: blue;">using</span> System.Drawing;
<span style="color: blue;">using</span> System.Runtime.InteropServices;
<span style="color: blue;">using</span> ESRI.ArcGIS.esriSystem;
<span style="color: blue;">using</span> ESRI.ArcGIS.Server;
<span style="color: blue;">using</span> ESRI.ArcGIS.SOESupport;
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.NamingRules"</span>, <span style="color: #a31515;">"SA1305:FieldNamesMustNotUseHungarianNotation"</span>, Justification = <span style="color: #a31515;">"Reviewed."</span>)]
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.NamingRules"</span>, <span style="color: #a31515;">"SA1306:FieldNamesMustBeginWithLowerCaseLetter"</span>, Justification = <span style="color: #a31515;">"Reviewed."</span>)]
[<span style="color: #2b91af;">ComVisible</span>(<span style="color: blue;">true</span>)]
[<span style="color: #2b91af;">Guid</span>(<span style="color: #a31515;">"b7058a41-e897-4151-bced-82ab9a03f2f9"</span>)]
[<span style="color: #2b91af;">ClassInterface</span>(<span style="color: #2b91af;">ClassInterfaceType</span>.None)]
[<span style="color: #2b91af;">ServerObjectInterceptor</span>(<span style="color: #a31515;">"MapServer"</span>, Description = <span style="color: #a31515;">"Watermark SOI"</span>, DisplayName = <span style="color: #a31515;">"Watermark SOI"</span>, Properties = <span style="color: #a31515;">""</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">Watermark</span> : <span style="color: #2b91af;">IServerObjectExtension</span>, <span style="color: #2b91af;">IRESTRequestHandler</span>, <span style="color: #2b91af;">IWebRequestHandler</span>, <span style="color: #2b91af;">IRequestHandler2</span>, <span style="color: #2b91af;">IRequestHandler</span>
{
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> server object interceptor name</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> soiName;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> server object Helper</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerObjectHelper</span> soHelper;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> server log</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">ServerLogger</span> serverLog;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> extension cache of service</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">IServerObjectExtension</span>> extensionCache = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: #2b91af;">IServerObjectExtension</span>>();
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> server Environment</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerEnvironment2</span> serverEnvironment;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> the first output directory ArcGIS server</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> outputDirectory = <span style="color: blue;">string</span>.Empty;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Initializes a new instance of the </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"Watermark"</span><span style="color: grey;">/></span><span style="color: green;"> class</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> Watermark()
{
<span style="color: blue;">this</span>.soiName = <span style="color: blue;">this</span>.GetType().Name;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Gets Server Environment</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerEnvironment2</span> ServerEnvironment
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.serverEnvironment == <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">UID</span> uid = <span style="color: blue;">new</span> <span style="color: #2b91af;">UIDClass</span>();
uid.Value = <span style="color: #a31515;">"{32D4C328-E473-4615-922C-63C108F55E60}"</span>;
<span style="color: green;">// CoCreate an EnvironmentManager and retrieve the IServerEnvironment</span>
<span style="color: #2b91af;">IEnvironmentManager</span> environmentManager = <span style="color: blue;">new</span> <span style="color: #2b91af;">EnvironmentManager</span>() <span style="color: blue;">as</span> <span style="color: #2b91af;">IEnvironmentManager</span>;
<span style="color: blue;">this</span>.serverEnvironment = environmentManager.GetEnvironment(uid) <span style="color: blue;">as</span> <span style="color: #2b91af;">IServerEnvironment2</span>;
}
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.serverEnvironment;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> initialize of server object interceptor</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"pSOH"</span><span style="color: grey;">></span><span style="color: green;">Server Object Helper</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Init(<span style="color: #2b91af;">IServerObjectHelper</span> pSOH)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">this</span>.soHelper = pSOH;
<span style="color: blue;">this</span>.serverLog = <span style="color: blue;">new</span> <span style="color: #2b91af;">ServerLogger</span>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">var</span> se4 = <span style="color: blue;">this</span>.ServerEnvironment <span style="color: blue;">as</span> <span style="color: #2b91af;">IServerEnvironmentEx</span>;
<span style="color: blue;">var</span> dirInfos = se4.GetServerDirectoryInfos();
dirInfos.Reset();
<span style="color: blue;">object</span> dirInfo = dirInfos.Next();
<span style="color: blue;">while</span> (dirInfo != <span style="color: blue;">null</span>)
{
<span style="color: blue;">var</span> dinfo2 = dirInfo <span style="color: blue;">as</span> <span style="color: #2b91af;">IServerDirectoryInfo2</span>;
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> != dinfo2 && dinfo2.Type == <span style="color: #2b91af;">esriServerDirectoryType</span>.esriSDTypeOutput)
{
<span style="color: blue;">this</span>.outputDirectory = dinfo2.Path;
<span style="color: blue;">break</span>;
}
dirInfo = dirInfos.Next();
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">this</span>.outputDirectory = <span style="color: blue;">string</span>.Empty;
}
<span style="color: blue;">this</span>.outputDirectory = <span style="color: blue;">this</span>.outputDirectory.Trim();
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.IsNullOrEmpty(<span style="color: blue;">this</span>.outputDirectory))
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".init()"</span>, 500, <span style="color: #a31515;">"OutputDirectory is empty or missing. Reset to default."</span>);
<span style="color: blue;">this</span>.outputDirectory = <span style="color: #a31515;">"C:\\arcgisserver\\directories\\arcgisoutput"</span>;
}
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoDetailed, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".init()"</span>, 500, <span style="color: #a31515;">"OutputDirectory is "</span> + <span style="color: blue;">this</span>.outputDirectory);
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Initialized "</span> + <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">" SOI."</span>);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".HandleRESTRequest()"</span>, 500, <span style="color: #a31515;">"Exception "</span> + e.GetType().Name + <span style="color: #a31515;">" "</span> + e.Message + <span style="color: #a31515;">" "</span> + e.StackTrace);
<span style="color: blue;">throw</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> shutdown server object interceptor</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Shutdown()
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Shutting down "</span> + <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">" SOI."</span>);
}
<span style="color: blue;"> #region</span> REST interceptors
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> get schema</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">return schema</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">string</span> GetSchema()
{
<span style="color: #2b91af;">IRESTRequestHandler</span> restRequestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRESTRequestHandler</span>>();
<span style="color: blue;">if</span> (restRequestHandler == <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">return</span> restRequestHandler.GetSchema();
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> handling rest request</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"Capabilities"</span><span style="color: grey;">></span><span style="color: green;">list of capabilities</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"resourceName"</span><span style="color: grey;">></span><span style="color: green;">name of resource</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationName"</span><span style="color: grey;">></span><span style="color: green;">name of operation</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationInput"</span><span style="color: grey;">></span><span style="color: green;">input operation</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">output format</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">request properties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">response properties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleRESTRequest(<span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> resourceName, <span style="color: blue;">string</span> operationName, <span style="color: blue;">string</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
<span style="color: blue;">try</span>
{
responseProperties = <span style="color: blue;">null</span>;
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".HandleRESTRequest()"</span>, 200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for handleRESTRequest"</span>);
<span style="color: green;">// Add code to manipulate REST requests here</span>
<span style="color: green;">// Find the correct delegate to forward the request too</span>
<span style="color: #2b91af;">IRESTRequestHandler</span> restRequestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRESTRequestHandler</span>>();
<span style="color: blue;">if</span> (restRequestHandler == <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">var</span> response = restRequestHandler.HandleRESTRequest(Capabilities, resourceName, operationName, operationInput, outputFormat, requestProperties, <span style="color: blue;">out</span> responseProperties);
<span style="color: green;">// Manipulate the response.</span>
<span style="color: green;">// Add watermark</span>
<span style="color: blue;">if</span> (operationName.Equals(<span style="color: #a31515;">"export"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: #2b91af;">Image</span> sourceImage = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (outputFormat.Equals(<span style="color: #a31515;">"image"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
sourceImage = <span style="color: #2b91af;">Image</span>.FromStream(<span style="color: blue;">new</span> System.IO.<span style="color: #2b91af;">MemoryStream</span>(response));
<span style="color: blue;">var</span> watermarker = <span style="color: blue;">new</span> <span style="color: #2b91af;">ApplyWatermark</span>();
<span style="color: blue;">var</span> watermarkedImage = watermarker.Mark(sourceImage, <span style="color: #a31515;">"(c) ESRI Inc."</span>);
<span style="color: blue;">var</span> newResponse = <span style="color: blue;">new</span> System.IO.<span style="color: #2b91af;">MemoryStream</span>();
watermarkedImage.Save(newResponse, sourceImage.RawFormat);
<span style="color: blue;">return</span> newResponse.GetBuffer();
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (outputFormat.Equals(<span style="color: #a31515;">"json"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: blue;">var</span> responseString = System.Text.<span style="color: #2b91af;">Encoding</span>.UTF8.GetString(response);
<span style="color: blue;">var</span> jo = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>(responseString);
<span style="color: blue;">string</span> hrefString = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (!jo.TryGetString(<span style="color: #a31515;">"href"</span>, <span style="color: blue;">out</span> hrefString))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">RESTErrorException</span>(<span style="color: #a31515;">"Export operation returned invalid response"</span>);
}
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.IsNullOrEmpty(hrefString))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">RESTErrorException</span>(<span style="color: #a31515;">"Export operation returned invalid response"</span>);
}
<span style="color: green;">// Generate output file location</span>
<span style="color: blue;">var</span> outputImageFileLocation = <span style="color: blue;">this</span>.GetOutputImageFileLocation(hrefString);
<span style="color: blue;">var</span> watermarker = <span style="color: blue;">new</span> <span style="color: #2b91af;">ApplyWatermark</span>();
<span style="color: #2b91af;">Image</span> watermarkedImage;
System.Drawing.Imaging.<span style="color: #2b91af;">ImageFormat</span> sourceImageFormat;
<span style="color: blue;">using</span> (sourceImage = <span style="color: #2b91af;">Image</span>.FromFile(outputImageFileLocation))
{
sourceImageFormat = sourceImage.RawFormat;
watermarkedImage = watermarker.Mark(sourceImage, <span style="color: #a31515;">"(c) ESRI Inc."</span>);
}
<span style="color: green;">// make sure we dispose sourceImage handles before saving to it</span>
watermarkedImage.Save(outputImageFileLocation, sourceImageFormat);
watermarkedImage.Dispose();
<span style="color: green;">// return response as is because we have modified the file its pointing to</span>
<span style="color: blue;">return</span> response;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (outputFormat.Equals(<span style="color: #a31515;">"kmz"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: green;">// Note: Watermark can be added for the kmz format too. In this example we didn't</span>
<span style="color: green;">// implement it.</span>
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">RESTErrorException</span>(<span style="color: #a31515;">"Kmz format is not supported"</span>);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">RESTErrorException</span>(<span style="color: #a31515;">"Invalid operation parameters"</span>);
}
}
<span style="color: blue;">return</span> response;
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">RESTErrorException</span> restException)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\":\"text/plain;charset=utf-8\"}"</span>;
<span style="color: blue;">return</span> System.Text.<span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(restException.Message);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".HandleRESTRequest()"</span>, 500, <span style="color: #a31515;">"Exception "</span> + e.GetType().Name + <span style="color: #a31515;">" "</span> + e.Message + <span style="color: #a31515;">" "</span> + e.StackTrace);
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> SOAP interceptors
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> handling OGC request</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"httpMethod"</span><span style="color: grey;">></span><span style="color: green;">http Method</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestURL"</span><span style="color: grey;">></span><span style="color: green;">request URL</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"queryString"</span><span style="color: grey;">></span><span style="color: green;">query string</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"Capabilities"</span><span style="color: grey;">></span><span style="color: green;">list of capabilities</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestData"</span><span style="color: grey;">></span><span style="color: green;">request data</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseContentType"</span><span style="color: grey;">></span><span style="color: green;">response content type</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"respDataType"</span><span style="color: grey;">></span><span style="color: green;">response data type</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleStringWebRequest(<span style="color: #2b91af;">esriHttpMethod</span> httpMethod, <span style="color: blue;">string</span> requestURL, <span style="color: blue;">string</span> queryString, <span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> requestData, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseContentType, <span style="color: blue;">out</span> <span style="color: #2b91af;">esriWebResponseDataType</span> respDataType)
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".HandleStringWebRequest()"</span>, 200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleStringWebRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IWebRequestHandler</span> webRequestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IWebRequestHandler</span>>();
<span style="color: blue;">if</span> (webRequestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> webRequestHandler.HandleStringWebRequest(httpMethod, requestURL, queryString, Capabilities, requestData, <span style="color: blue;">out</span> responseContentType, <span style="color: blue;">out</span> respDataType);
}
responseContentType = <span style="color: blue;">null</span>;
respDataType = <span style="color: #2b91af;">esriWebResponseDataType</span>.esriWRDTPayload;
<span style="color: green;">// Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> handling soap binary </span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"request"</span><span style="color: grey;">></span><span style="color: green;">request</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleBinaryRequest(<span style="color: blue;">ref</span> <span style="color: blue;">byte</span>[] request)
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".HandleBinaryRequest()"</span>, 200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleBinaryRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IRequestHandler</span> requestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> requestHandler.HandleBinaryRequest(request);
}
<span style="color: green;">// Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> handling soap binary </span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"Capabilities"</span><span style="color: grey;">></span><span style="color: green;">list of capabilities</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"request"</span><span style="color: grey;">></span><span style="color: green;">request</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleBinaryRequest2(<span style="color: blue;">string</span> Capabilities, <span style="color: blue;">ref</span> <span style="color: blue;">byte</span>[] request)
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".HandleBinaryRequest2()"</span>, 200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleBinaryRequest2"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IRequestHandler2</span> requestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler2</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> requestHandler.HandleBinaryRequest2(Capabilities, request);
}
<span style="color: green;">// Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> handler soap xml</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"Capabilities"</span><span style="color: grey;">></span><span style="color: green;">list of capabilities</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"request"</span><span style="color: grey;">></span><span style="color: green;">request</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">string</span> HandleStringRequest(<span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> request)
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".HandleStringRequest()"</span>, 200, <span style="color: #a31515;">"Request received in Sample Object Interceptor for HandleStringRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate requests here</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IRequestHandler</span> requestHandler = FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">return</span> requestHandler.HandleStringRequest(Capabilities, request);
}
<span style="color: green;">// Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> Utility code
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> find handler rest for server object or server object extension</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><typeparam name=</span><span style="color: grey;">"THandlerInterface"</span><span style="color: grey;">></span><span style="color: green;">interface that implements handler rest</span><span style="color: grey;"></typeparam></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">object that implements handler rest</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> THandlerInterface FindRequestHandlerDelegate<THandlerInterface>() <span style="color: blue;">where</span> THandlerInterface : <span style="color: blue;">class</span>
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">IPropertySet</span> props = <span style="color: blue;">this</span>.ServerEnvironment.Properties;
<span style="color: blue;">string</span> extensionName;
<span style="color: blue;">try</span>
{
extensionName = (<span style="color: blue;">string</span>)props.GetProperty(<span style="color: #a31515;">"ExtensionName"</span>);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> <span style="color: green;">/*e*/</span>)
{
extensionName = <span style="color: blue;">null</span>;
}
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.IsNullOrEmpty(extensionName))
{
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.soHelper.ServerObject <span style="color: blue;">as</span> THandlerInterface;
}
<span style="color: green;">// Get the extension reference from cache if available</span>
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.extensionCache.ContainsKey(extensionName))
{
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.extensionCache[extensionName] <span style="color: blue;">as</span> THandlerInterface;
}
<span style="color: green;">// This request is to be made on a specific extension</span>
<span style="color: green;">// so we find the extension from the extension manager</span>
<span style="color: #2b91af;">IServerObjectExtensionManager</span> extnMgr = <span style="color: blue;">this</span>.soHelper.ServerObject <span style="color: blue;">as</span> <span style="color: #2b91af;">IServerObjectExtensionManager</span>;
<span style="color: #2b91af;">IServerObjectExtension</span> soe = extnMgr.FindExtensionByTypeName(extensionName);
<span style="color: blue;">return</span> soe <span style="color: blue;">as</span> THandlerInterface;
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">this</span>.serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, <span style="color: blue;">this</span>.soiName + <span style="color: #a31515;">".FindRequestHandlerDelegate()"</span>, 500, e.ToString());
<span style="color: blue;">throw</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Generate physical file path from virtual path</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"virtualPath"</span><span style="color: grey;">></span><span style="color: green;">virtualPath Path returned by the MapServer SO</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">physical file path</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> GetOutputImageFileLocation(<span style="color: blue;">string</span> virtualPath)
{
<span style="color: green;">/*</span>
<span style="color: green;"> * Sample output returned by MapServer SO</span>
<span style="color: green;"> * example : /rest/directories/arcgisoutput/SampleWorldCities_MapServer/</span>
<span style="color: green;"> * _ags_map26c62f8c2c0c4965b53e87e300e1912f.png</span>
<span style="color: green;"> */</span>
<span style="color: blue;">var</span> virtualPathParts = virtualPath.Split(<span style="color: #a31515;">'/'</span>);
<span style="color: blue;">string</span> imageFileLocation = <span style="color: blue;">this</span>.outputDirectory;
<span style="color: green;">// build the physical path to the image file</span>
<span style="color: blue;">bool</span> buildPath = <span style="color: blue;">false</span>;
<span style="color: blue;">foreach</span> (<span style="color: blue;">string</span> virtualPathPart <span style="color: blue;">in</span> virtualPathParts)
{
<span style="color: blue;">if</span> (buildPath)
{
imageFileLocation += <span style="color: #a31515;">"\\"</span> + virtualPathPart;
}
<span style="color: blue;">if</span> (virtualPathPart.Equals(<span style="color: #a31515;">"arcgisoutput"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
buildPath = <span style="color: blue;">true</span>;
}
}
<span style="color: blue;">return</span> imageFileLocation;
}
<span style="color: blue;"> #endregion</span>
}
}</pre>
<br />
Nel codice possiamo notare come, una volta disponibile la risposta dal SO, aggiungiamo il watermark all'immagine prima di inviarla al client.<br />
<br />
Una volta compilato lo installiamo in ArcGIS Server Manager come avviene per le SOE.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFzJ-V8fJpIbiNANUm2Z93h4DPF1OS-CoT_8G_x66aGZ5xv3jENTOisIMpmnlHye7OpxYTi-qisqcdn-jYv5ofU9WDe3CXMfRDr-rxOhSt0lofXlIh6FJX-XTH_gBYxa2biNSRLa1kQp1D/s1600/Cattura2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFzJ-V8fJpIbiNANUm2Z93h4DPF1OS-CoT_8G_x66aGZ5xv3jENTOisIMpmnlHye7OpxYTi-qisqcdn-jYv5ofU9WDe3CXMfRDr-rxOhSt0lofXlIh6FJX-XTH_gBYxa2biNSRLa1kQp1D/s640/Cattura2.PNG" width="640" /></a></div>
<br />
e successivamente abilitiamo il SOI nel servizio GIS.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5Np0F7Cz2ll96KKsMXPoJVhCf2I9xK5_mer-OQ3e3o7qGJ9KEINnVJ4TBqfnRjedXnPLQyI49fEaKU3jSXuPlqySQIojAW6oWVMi_a2BzASSX6JfysP_X582TNpT8RxVGN1aL0CbVBX1L/s1600/Cattura3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5Np0F7Cz2ll96KKsMXPoJVhCf2I9xK5_mer-OQ3e3o7qGJ9KEINnVJ4TBqfnRjedXnPLQyI49fEaKU3jSXuPlqySQIojAW6oWVMi_a2BzASSX6JfysP_X582TNpT8RxVGN1aL0CbVBX1L/s640/Cattura3.PNG" width="640" /></a></div>
<br />
<br />
Possiamo effettuare il test direttamente dall'export del Rest Services Directory<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhafQZl2-fSAOTxaDw_G-V34EdE7xYU6tDjeWyYywnbzOZ5zLwtfT-cJkvjQvmB9qbDLvDFFZYvinMpPzbj1_KrsJGR7q-vkxabXv57cYrpEdVQa6oMZXS4AixppOFexbQOad6jAgL6smdO/s1600/watermark.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="534" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhafQZl2-fSAOTxaDw_G-V34EdE7xYU6tDjeWyYywnbzOZ5zLwtfT-cJkvjQvmB9qbDLvDFFZYvinMpPzbj1_KrsJGR7q-vkxabXv57cYrpEdVQa6oMZXS4AixppOFexbQOad6jAgL6smdO/s640/watermark.png" width="640" /></a></div>
<br />
<br />
Link <a href="http://sit5.sistemigis.it/sit/rest/services/SampleWorldCities/MapServer/export?bbox=-104.53020709870626,-25.471925275660684,75.35704494206294,51.908146633940035" target="_blank">live demo</a><br />
<br />
Mentre in questo esempio vediamo una <a href="http://it.wikipedia.org/wiki/Proof_of_concept" target="_blank">PoC</a> di come gestire un controllo a livello di layer basato su permessi impostati su file esterno.<br />
Se si implementa il controllo a livello di layer attraverso un SOI, occorre anche disabilitare il caching di tutti i layer delle risorse inclusi nel servizio. Questo consente di intercettare le operazione e filtrare i layer che non sono consentiti. Nell'ArcGIS Server Administrator Directory occorre impostare la proprietà <em>disableCaching</em> a true del servizio .<br />I passi da seguire nel dettaglio sono:<br />- Aprire l'ArcGIS Server Administrator Directory (l'url è <a href="http://myserver:6080/arcgis/admin">http://myserver:6080/arcgis/admin</a>);<br />- cliccare su services e cliccare il nome del servizio interessato;<br />- cliccare edit;<br />- nella sezione properties del json del servizio, aggiungere la proprietà disableCaching ed impostare il valore a true<br />
"properties": {<br /> ...<br /> "disableCaching": "true",<br /> ...<br /> },<br />
- cliccare save Edits. <br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">NetLayerAccessSOI</span> : <span style="color: #2b91af;">IServerObjectExtension</span>, <span style="color: #2b91af;">IRESTRequestHandler</span>, <span style="color: #2b91af;">IWebRequestHandler</span>, <span style="color: #2b91af;">IRequestHandler2</span>, <span style="color: #2b91af;">IRequestHandler</span>
{
<span style="color: blue;">private</span> <span style="color: blue;">string</span> _soiName;
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerObjectHelper</span> _soHelper;
<span style="color: blue;">private</span> <span style="color: #2b91af;">ServerLogger</span> _serverLog;
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerObject</span> _serverObject;
<span style="color: #2b91af;">RestServiceSOI</span> _restServiceSOI;
<span style="color: #2b91af;">SoapServiceSOI</span> _soapServiceSOI;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">RESTHandlerOpCode</span>, <span style="color: #2b91af;">RestFilterOperation</span>> _operationMap;
<span style="color: green;">/*</span>
<span style="color: green;"> * Map used to store permission information. Permission rules for each</span>
<span style="color: green;"> * service is read form the permisson.json file.</span>
<span style="color: green;"> */</span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">String</span>, <span style="color: #2b91af;">String</span>> _servicePermissionMap = <span style="color: blue;">null</span>;
<span style="color: green;">/*</span>
<span style="color: green;"> * Permission are read from this external file. Advantage of an external file is that </span>
<span style="color: green;"> * same SOI can be used for multiple services and permission for all of these services</span>
<span style="color: green;"> * is read from the permission.json file. </span>
<span style="color: green;"> * </span>
<span style="color: green;"> */</span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">String</span> _permissionFilePath = <span style="color: #a31515;">"C:\\arcgisserver\\permission.json"</span>; <span style="color: green;">//default path</span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">String</span> _wsdlFilePath = <span style="color: #a31515;">"C:\\Program Files\\ArcGIS\\Server\\XmlSchema\\MapServer.wsdl"</span>; <span style="color: green;">//default path</span>
<span style="color: blue;">public</span> NetLayerAccessSOI ()
{
_soiName = <span style="color: blue;">this</span>.GetType().Name;
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> InitFiltering ()
{
_operationMap = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">RESTHandlerOpCode</span>, <span style="color: #2b91af;">RestFilterOperation</span>>
{
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.root, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = <span style="color: blue;">null</span>,
PostFilter = PostFilterRESTRoot
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootExport, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = PreFilterExport,
PostFilter = <span style="color: blue;">null</span>
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootFind, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = PreFilterFindAndKml,
PostFilter = <span style="color: blue;">null</span>
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootGenerateKml, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = PreFilterFindAndKml,
PostFilter = <span style="color: blue;">null</span>
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootIdentify, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = PreFilterIdentify,
PostFilter = <span style="color: blue;">null</span>
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootLayers, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = <span style="color: blue;">null</span>,
PostFilter = PostFilterRootLayers
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootLegend, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = <span style="color: blue;">null</span>,
PostFilter = PostFilterRootLegend
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.layerGenerateRenderer, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = PreFilterLayerQuery,
PostFilter = <span style="color: blue;">null</span>
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.layerQuery, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = PreFilterLayerQuery,
PostFilter = <span style="color: blue;">null</span>
} },
{ <span style="color: #2b91af;">RESTHandlerOpCode</span>.layerQueryRelatedRecords, <span style="color: blue;">new</span> <span style="color: #2b91af;">RestFilterOperation</span>
{
PreFilter = PreFilterLayerQuery,
PostFilter = <span style="color: blue;">null</span>
} }
};
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Init ( <span style="color: #2b91af;">IServerObjectHelper</span> pSOH )
{
<span style="color: blue;">try</span>
{
_soHelper = pSOH;
_serverLog = <span style="color: blue;">new</span> <span style="color: #2b91af;">ServerLogger</span>();
_serverObject = pSOH.ServerObject;
_restServiceSOI = <span style="color: blue;">new</span> <span style="color: #2b91af;">RestServiceSOI</span>(_soHelper);
_soapServiceSOI = <span style="color: blue;">new</span> <span style="color: #2b91af;">SoapServiceSOI</span>(_soHelper, _wsdlFilePath);
<span style="color: blue;">if</span> (<span style="color: #2b91af;">File</span>.Exists(_permissionFilePath))
{
<span style="color: green;">//TODO REMOVE</span>
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Reading permissions from "</span> + _permissionFilePath);
_servicePermissionMap = ReadPermissionFile(_permissionFilePath);
<span style="color: green;">//TODO REMOVE</span>
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Total permission entries: "</span> + _servicePermissionMap.Count());
}
<span style="color: blue;">else</span>
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, _soiName + <span style="color: #a31515;">".init()"</span>, 500, <span style="color: #a31515;">"Permission file does not exist at "</span> + _permissionFilePath);
}
InitFiltering();
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Initialized "</span> + _soiName + <span style="color: #a31515;">" SOI."</span>);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, _soiName + <span style="color: #a31515;">".init()"</span>, 500, <span style="color: #a31515;">"Exception: "</span> + e.Message + <span style="color: #a31515;">" in "</span> + e.StackTrace);
}
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Shutdown ()
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".init()"</span>, 200, <span style="color: #a31515;">"Shutting down "</span> + _soiName + <span style="color: #a31515;">" SOE."</span>);
}
<span style="color: blue;"> #region</span> REST interceptors
<span style="color: blue;">public</span> <span style="color: blue;">string</span> GetSchema ()
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">IRESTRequestHandler</span> restRequestHandler = _restServiceSOI.FindRequestHandlerDelegate<<span style="color: #2b91af;">IRESTRequestHandler</span>>();
<span style="color: blue;">if</span> (restRequestHandler == <span style="color: blue;">null</span>)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: blue;">return</span> restRequestHandler.GetSchema();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, _soiName + <span style="color: #a31515;">".GetSchema()"</span>, 500, <span style="color: #a31515;">"Exception: "</span> + e.Message + <span style="color: #a31515;">" in "</span> + e.StackTrace);
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">byte</span>[] FilterRESTRequest (
<span style="color: #2b91af;">RestFilterOperation</span> restFilterOp,
<span style="color: #2b91af;">RESTRequestParameters</span> restInput,
<span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayers,
<span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties )
{
<span style="color: blue;">try</span>
{
responseProperties = <span style="color: blue;">null</span>;
<span style="color: #2b91af;">IRESTRequestHandler</span> restRequestHandler = _restServiceSOI.FindRequestHandlerDelegate<<span style="color: #2b91af;">IRESTRequestHandler</span>>();
<span style="color: blue;">if</span> (restRequestHandler == <span style="color: blue;">null</span>)
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">RESTErrorException</span>(<span style="color: #a31515;">"Service handler not found"</span>);
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> != restFilterOp && <span style="color: blue;">null</span> != restFilterOp.PreFilter)
restInput = restFilterOp.PreFilter(restInput, authorizedLayers);
<span style="color: blue;">byte</span>[] response =
restRequestHandler.HandleRESTRequest(restInput.Capabilities, restInput.ResourceName, restInput.OperationName, restInput.OperationInput,
restInput.OutputFormat, restInput.RequestProperties, <span style="color: blue;">out</span> responseProperties);
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == restFilterOp || <span style="color: blue;">null</span> == restFilterOp.PostFilter)
<span style="color: blue;">return</span> response;
<span style="color: #2b91af;">String</span> responseStr = System.Text.<span style="color: #2b91af;">Encoding</span>.UTF8.GetString(response);
responseStr = restFilterOp.PostFilter(restInput, responseStr, authorizedLayers);
<span style="color: green;">// TODO: remove ------------------------------------</span>
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoDetailed, <span style="color: #a31515;">"HandleRESTRequest.FilterRESTRequest"</span>, 0, <span style="color: #a31515;">"Filtered REST resource response :: "</span> + responseStr);
<span style="color: green;">// TODO: remove ------------------------------------</span>
<span style="color: blue;">return</span> System.Text.<span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(responseStr);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">RESTErrorException</span> restException)
{
<span style="color: green;">// pre- or post- filters can throw restException with the error JSON output in the Message property.</span>
<span style="color: green;">// we catch them here and return JSON response.</span>
responseProperties = <span style="color: #a31515;">"{\"Content-Type\":\"text/plain;charset=utf-8\"}"</span>;
<span style="color: green;">//catch and return a JSON error from the pre- or postFilter.</span>
<span style="color: blue;">return</span> System.Text.<span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(restException.Message);
}
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">RESTHandlerOpCode</span> GetHandlerOpCode ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput )
{
<span style="color: blue;">var</span> resName = restInput.ResourceName.TrimStart(<span style="color: #a31515;">'/'</span>); <span style="color: green;">//remove leading '/' to prevent empty string at index 0</span>
<span style="color: blue;">var</span> resourceTokens = (resName ?? <span style="color: #a31515;">""</span>).ToLower().Split(<span style="color: #a31515;">'/'</span>);
<span style="color: blue;">string</span> opName = (restInput.OperationName ?? <span style="color: #a31515;">""</span>).ToLower();
<span style="color: blue;">switch</span> (resourceTokens[0])
{
<span style="color: blue;">case</span> <span style="color: #a31515;">""</span>:
<span style="color: blue;">switch</span> (opName)
{
<span style="color: blue;">case</span> <span style="color: #a31515;">""</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.root;
<span style="color: blue;">case</span> <span style="color: #a31515;">"export"</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootExport;
<span style="color: blue;">case</span> <span style="color: #a31515;">"find"</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootFind;
<span style="color: blue;">case</span> <span style="color: #a31515;">"identify"</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootIdentify;
<span style="color: blue;">case</span> <span style="color: #a31515;">"generatekml"</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootGenerateKml;
<span style="color: blue;">default</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.defaultNoOp;
}
<span style="color: blue;">case</span> <span style="color: #a31515;">"layers"</span>:
{
<span style="color: blue;">var</span> tokenCount = resourceTokens.GetLength(0);
<span style="color: blue;">if</span> (1 == tokenCount)
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootLayers;
<span style="color: blue;">if</span> (2 == tokenCount)
<span style="color: blue;">switch</span> (opName)
{
<span style="color: blue;">case</span> <span style="color: #a31515;">""</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.layerRoot;
<span style="color: blue;">case</span> <span style="color: #a31515;">"query"</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.layerQuery;
<span style="color: blue;">case</span> <span style="color: #a31515;">"queryRelatedRecords"</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.layerQueryRelatedRecords;
<span style="color: blue;">default</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.defaultNoOp;
}
}
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #a31515;">"legend"</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.rootLegend;
<span style="color: blue;">default</span>:
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.defaultNoOp;
}
<span style="color: blue;">return</span> <span style="color: #2b91af;">RESTHandlerOpCode</span>.defaultNoOp;
}
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleRESTRequest ( <span style="color: blue;">string</span> capabilities, <span style="color: blue;">string</span> resourceName, <span style="color: blue;">string</span> operationName,
<span style="color: blue;">string</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties )
{
<span style="color: blue;">try</span>
{
responseProperties = <span style="color: blue;">null</span>;
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleRESTRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Layer Access SOI for handleRESTRequest"</span>);
<span style="color: blue;">var</span> authorizedLayerSet = GetAuthorizedLayers(_restServiceSOI);
<span style="color: blue;">var</span> restInput = <span style="color: blue;">new</span> <span style="color: #2b91af;">RESTRequestParameters</span>
{
Capabilities = capabilities,
ResourceName = resourceName,
OperationName = operationName,
OperationInput = operationInput,
OutputFormat = outputFormat,
RequestProperties = requestProperties
};
<span style="color: blue;">var</span> opCode = GetHandlerOpCode(restInput);
<span style="color: #2b91af;">RestFilterOperation</span> filterOp = _operationMap.ContainsKey(opCode) ? _operationMap[opCode] : <span style="color: blue;">null</span>;
<span style="color: blue;">return</span> FilterRESTRequest(filterOp, restInput, authorizedLayerSet, <span style="color: blue;">out</span> responseProperties);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, _soiName + <span style="color: #a31515;">".HandleRESTRequest()"</span>, 500, <span style="color: #a31515;">"Exception: "</span> + e.Message + <span style="color: #a31515;">" in "</span> + e.StackTrace);
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> REST Pre-filters
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">RESTRequestParameters</span> PreFilterExport ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput, <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayers )
{
<span style="color: #2b91af;">JavaScriptSerializer</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span> { MaxJsonLength = <span style="color: blue;">int</span>.MaxValue };
<span style="color: blue;">var</span> operationInputJson = sr.DeserializeObject(restInput.OperationInput) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
operationInputJson[<span style="color: #a31515;">"layers"</span>] = <span style="color: #a31515;">"show:"</span> + <span style="color: #2b91af;">String</span>.Join(<span style="color: #a31515;">","</span>, authorizedLayers);
restInput.OperationInput = sr.Serialize(operationInputJson);
<span style="color: blue;">return</span> restInput;
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">RESTRequestParameters</span> PreFilterFindAndKml ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput, <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayers )
{
<span style="color: #2b91af;">JavaScriptSerializer</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span> { MaxJsonLength = <span style="color: blue;">int</span>.MaxValue };
<span style="color: blue;">var</span> operationInputJson = sr.DeserializeObject(restInput.OperationInput) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> removeSpacesRegEx = <span style="color: blue;">new</span> <span style="color: #2b91af;">Regex</span>(<span style="color: #a31515;">"\\s+"</span>);
<span style="color: #2b91af;">String</span> requestedLayers = operationInputJson.ContainsKey(<span style="color: #a31515;">"layers"</span>) ? operationInputJson[<span style="color: #a31515;">"layers"</span>].ToString() : <span style="color: #a31515;">""</span>;
requestedLayers = removeSpacesRegEx.Replace(requestedLayers, <span style="color: #a31515;">""</span>);
operationInputJson[<span style="color: #a31515;">"layers"</span>] = RemoveUnauthorizedLayersFromRequestedLayers(requestedLayers, authorizedLayers);
restInput.OperationInput = sr.Serialize(operationInputJson);
<span style="color: blue;">return</span> restInput;
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">RESTRequestParameters</span> PreFilterIdentify ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput, <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayers )
{
<span style="color: #2b91af;">JavaScriptSerializer</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span> { MaxJsonLength = <span style="color: blue;">int</span>.MaxValue };
<span style="color: blue;">var</span> operationInputJson = sr.DeserializeObject(restInput.OperationInput) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: #2b91af;">String</span> requestedLayers = operationInputJson.ContainsKey(<span style="color: #a31515;">"layers"</span>) ? operationInputJson[<span style="color: #a31515;">"layers"</span>].ToString() : <span style="color: #a31515;">""</span>;
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.IsNullOrEmpty(requestedLayers) || requestedLayers.StartsWith(<span style="color: #a31515;">"top"</span>) || requestedLayers.StartsWith(<span style="color: #a31515;">"all"</span>))
{
operationInputJson[<span style="color: #a31515;">"layers"</span>] = <span style="color: #a31515;">"visible:"</span> + authorizedLayers;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (requestedLayers.StartsWith(<span style="color: #a31515;">"visible"</span>))
{
<span style="color: blue;">var</span> reqLayerParts = requestedLayers.Split(<span style="color: #a31515;">':'</span>);
<span style="color: blue;">var</span> removeSpacesRegEx = <span style="color: blue;">new</span> <span style="color: #2b91af;">Regex</span>(<span style="color: #a31515;">"\\s+"</span>);
operationInputJson[<span style="color: #a31515;">"layers"</span>] = <span style="color: #a31515;">"visible:"</span> +
RemoveUnauthorizedLayersFromRequestedLayers(
removeSpacesRegEx.Replace(reqLayerParts[1], <span style="color: #a31515;">""</span>), authorizedLayers);
}
<span style="color: blue;">else</span>
{
operationInputJson[<span style="color: #a31515;">"layers"</span>] = <span style="color: #a31515;">"visible:"</span> + authorizedLayers;
}
restInput.OperationInput = sr.Serialize(operationInputJson);
<span style="color: blue;">return</span> restInput;
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">RESTRequestParameters</span> PreFilterLayerQuery ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput, <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayers )
{
<span style="color: #2b91af;">JavaScriptSerializer</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span> { MaxJsonLength = <span style="color: blue;">int</span>.MaxValue };
<span style="color: blue;">var</span> operationInputJson = sr.DeserializeObject(restInput.OperationInput) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> resName = restInput.ResourceName.TrimStart(<span style="color: #a31515;">'/'</span>);
<span style="color: blue;">var</span> rnameParts = resName.Split(<span style="color: #a31515;">'/'</span>);
<span style="color: blue;">var</span> requestedLayerId = rnameParts[1];
<span style="color: blue;">if</span> (!authorizedLayers.Contains(requestedLayerId))
{
<span style="color: blue;">var</span> errorReturn = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>
{
{<span style="color: #a31515;">"error"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>
{
{<span style="color: #a31515;">"code"</span>, 404},
{<span style="color: #a31515;">"message"</span>, <span style="color: #a31515;">"Access Denied"</span>}
}
}
};
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">RESTErrorException</span>(sr.Serialize(errorReturn));
}
restInput.OperationInput = sr.Serialize(operationInputJson);
<span style="color: blue;">return</span> restInput;
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> REST Post-filters
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span>
<span style="color: grey;">///</span><span style="color: green;"> Filter REST root service info response.</span>
<span style="color: grey;">///</span><span style="color: green;"> IMPORTANT: the JSON structure returned by the REST handler root resource </span>
<span style="color: grey;">///</span><span style="color: green;"> differs from what you usually see as the response from the service REST endpoint.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"restInput"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"originalResponse"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"authorizedLayerSet"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">Filtered json</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">String</span> PostFilterRESTRoot ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput, <span style="color: #2b91af;">String</span> originalResponse, <span style="color: #2b91af;">HashSet</span><<span style="color: #2b91af;">String</span>> authorizedLayerSet )
{
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == authorizedLayerSet)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: green;">//restInput is not used here, but may be used later as needed</span>
<span style="color: blue;">try</span>
{
<span style="color: green;">// Perform JSON filtering</span>
<span style="color: green;">// Note: The JSON syntax can change and you might have to adjust this piece of code accordingly</span>
<span style="color: blue;">if</span> (authorizedLayerSet == <span style="color: blue;">null</span>)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: green;">/*</span>
<span style="color: green;"> * Remove unauthorized layer information from 1. Under 'contents' tag 2. Under 'resources' tag</span>
<span style="color: green;"> * 2.1 'layers' 2.2 'tables' 2.3 'legend'</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">JavaScriptSerializer</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span> { MaxJsonLength = <span style="color: blue;">int</span>.MaxValue };
<span style="color: blue;">var</span> jsonResObj = sr.DeserializeObject(originalResponse) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: green;">// Filter for 'contents' tag</span>
<span style="color: blue;">var</span> contentsJO = jsonResObj[<span style="color: #a31515;">"contents"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> layersJA = contentsJO[<span style="color: #a31515;">"layers"</span>] <span style="color: blue;">as</span> <span style="color: blue;">object</span>[];
<span style="color: blue;">var</span> updatedLayers = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">object</span>>();
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> layerO <span style="color: blue;">in</span> layersJA)
{
<span style="color: blue;">var</span> layerJO = layerO <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> id = layerJO[<span style="color: #a31515;">"id"</span>].ToString();
<span style="color: blue;">if</span> (authorizedLayerSet.Contains(id))
{
updatedLayers.Add(layerJO);
}
}
contentsJO[<span style="color: #a31515;">"layers"</span>] = updatedLayers.ToArray();
<span style="color: green;">// Filter for 'resources' tag, very simplified filtering, may fail if ordering changes</span>
<span style="color: blue;">var</span> allResourcesJA = jsonResObj[<span style="color: #a31515;">"resources"</span>] <span style="color: blue;">as</span> <span style="color: blue;">object</span>[];
<span style="color: blue;">var</span> layersRJO = allResourcesJA.FirstOrDefault(e =>
{
<span style="color: blue;">var</span> jo = e <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">if</span> (!jo.ContainsKey(<span style="color: #a31515;">"name"</span>))
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
<span style="color: blue;">var</span> name = jo[<span style="color: #a31515;">"name"</span>].ToString();
<span style="color: blue;">return</span> (<span style="color: #a31515;">"layers"</span> == name);
}) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> tablesRJO = allResourcesJA.FirstOrDefault(e =>
{
<span style="color: blue;">var</span> jo = e <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">if</span> (!jo.ContainsKey(<span style="color: #a31515;">"name"</span>))
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
<span style="color: blue;">var</span> name = jo[<span style="color: #a31515;">"name"</span>].ToString();
<span style="color: blue;">return</span> (<span style="color: #a31515;">"tables"</span> == name);
}) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> legendRJO = allResourcesJA.FirstOrDefault(e =>
{
<span style="color: blue;">var</span> jo = e <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">if</span> (!jo.ContainsKey(<span style="color: #a31515;">"name"</span>))
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
<span style="color: blue;">var</span> name = jo[<span style="color: #a31515;">"name"</span>].ToString();
<span style="color: blue;">return</span> (<span style="color: #a31515;">"legend"</span> == name);
}) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: green;">//filter and replace layers</span>
<span style="color: blue;">var</span> filteredLayerResourceJA = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">object</span>>();
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> != layersRJO)
{
<span style="color: green;">// Filter for 'resources -> layers -> resources' tag</span>
<span style="color: blue;">var</span> layerResourceJA = layersRJO[<span style="color: #a31515;">"resources"</span>] <span style="color: blue;">as</span> <span style="color: blue;">object</span>[];
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> lrJO <span style="color: blue;">in</span> layerResourceJA)
{
<span style="color: blue;">var</span> lrJODict = lrJO <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">if</span> (authorizedLayerSet.Contains(lrJODict[<span style="color: #a31515;">"name"</span>].ToString()))
{
filteredLayerResourceJA.Add(lrJO);
}
}
}
layersRJO[<span style="color: #a31515;">"resources"</span>] = filteredLayerResourceJA.ToArray();
<span style="color: green;">//filter and replace tables</span>
<span style="color: blue;">var</span> filteredTableResourceJA = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">object</span>>();
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> != tablesRJO)
{
<span style="color: green;">// Filter for 'resources -> tables -> resources' tag</span>
<span style="color: blue;">var</span> tableResourceJA = tablesRJO[<span style="color: #a31515;">"resources"</span>] <span style="color: blue;">as</span> <span style="color: blue;">object</span>[];
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> tbJO <span style="color: blue;">in</span> tableResourceJA)
{
<span style="color: blue;">var</span> tbJODict = tbJO <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">if</span> (authorizedLayerSet.Contains(tbJODict[<span style="color: #a31515;">"name"</span>].ToString()))
{
filteredTableResourceJA.Add(tbJO);
}
}
}
tablesRJO[<span style="color: #a31515;">"resources"</span>] = filteredTableResourceJA.ToArray();
<span style="color: green;">//filter and replace legend layers</span>
<span style="color: blue;">var</span> filteredLegendLayersRJA = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">object</span>>();
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> != legendRJO)
{
<span style="color: green;">// Filter for 'resources -> legend -> contents->layers' tag</span>
<span style="color: blue;">var</span> legendContentsJO = legendRJO[<span style="color: #a31515;">"contents"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> legendLayersJA = legendContentsJO[<span style="color: #a31515;">"layers"</span>] <span style="color: blue;">as</span> <span style="color: blue;">object</span>[];
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> lgJO <span style="color: blue;">in</span> legendLayersJA)
{
<span style="color: blue;">var</span> lgJODict = lgJO <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">if</span> (authorizedLayerSet.Contains(lgJODict[<span style="color: #a31515;">"layerId"</span>].ToString()))
{
filteredLegendLayersRJA.Add(lgJO);
}
}
legendContentsJO[<span style="color: #a31515;">"layers"</span>] = filteredLegendLayersRJA.ToArray();
}
<span style="color: green;">// Return the filter response</span>
<span style="color: blue;">return</span> sr.Serialize(jsonResObj);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ignore)
{
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> PostFilterRootLayers ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput, <span style="color: #2b91af;">String</span> originalResponse, <span style="color: #2b91af;">HashSet</span><<span style="color: #2b91af;">String</span>> authorizedLayerSet )
{
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == authorizedLayerSet)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: green;">//restInput is not used here, but may be used later as needed</span>
<span style="color: blue;">try</span>
{
<span style="color: green;">// Perform JSON filtering</span>
<span style="color: green;">// Note: The JSON syntax can change and you might have to adjust this piece of code accordingly</span>
<span style="color: blue;">if</span> (authorizedLayerSet == <span style="color: blue;">null</span>)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: green;">/*</span>
<span style="color: green;"> * Remove unauthorized layer information from 1. Under 'contents' tag 2. Under 'resources' tag</span>
<span style="color: green;"> * 2.1 'layers' 2.2 'tables' 2.3 'legend'</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">JavaScriptSerializer</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span> { MaxJsonLength = <span style="color: blue;">int</span>.MaxValue };
<span style="color: blue;">var</span> jsonResObj = sr.DeserializeObject(originalResponse) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: green;">// Filter for 'contents' tag</span>
<span style="color: blue;">var</span> layersJA = jsonResObj[<span style="color: #a31515;">"layers"</span>] <span style="color: blue;">as</span> <span style="color: blue;">object</span>[];
<span style="color: blue;">var</span> updatedLayers = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">object</span>>();
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> layerO <span style="color: blue;">in</span> layersJA)
{
<span style="color: blue;">var</span> layerJO = layerO <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> id = layerJO[<span style="color: #a31515;">"id"</span>].ToString();
<span style="color: blue;">if</span> (authorizedLayerSet.Contains(id))
{
updatedLayers.Add(layerJO);
}
}
jsonResObj[<span style="color: #a31515;">"layers"</span>] = updatedLayers.ToArray();
<span style="color: green;">// Return the filter response</span>
<span style="color: blue;">return</span> sr.Serialize(jsonResObj);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ignore)
{
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> PostFilterRootLegend ( <span style="color: #2b91af;">RESTRequestParameters</span> restInput, <span style="color: #2b91af;">String</span> originalResponse, <span style="color: #2b91af;">HashSet</span><<span style="color: #2b91af;">String</span>> authorizedLayerSet )
{
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == authorizedLayerSet)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: green;">//restInput is not used here, but may be used later as needed</span>
<span style="color: blue;">try</span>
{
<span style="color: green;">// Perform JSON filtering</span>
<span style="color: green;">// Note: The JSON syntax can change and you might have to adjust this piece of code accordingly</span>
<span style="color: blue;">if</span> (authorizedLayerSet == <span style="color: blue;">null</span>)
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: green;">/*</span>
<span style="color: green;"> * Remove unauthorized layer information from 1. Under 'contents' tag 2. Under 'resources' tag</span>
<span style="color: green;"> * 2.1 'layers' 2.2 'tables' 2.3 'legend'</span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">JavaScriptSerializer</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span> { MaxJsonLength = <span style="color: blue;">int</span>.MaxValue };
<span style="color: blue;">var</span> jsonResObj = sr.DeserializeObject(originalResponse) <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: green;">// Filter for 'contents' tag</span>
<span style="color: blue;">var</span> layersJA = jsonResObj[<span style="color: #a31515;">"layers"</span>] <span style="color: blue;">as</span> <span style="color: blue;">object</span>[];
<span style="color: blue;">var</span> updatedLayers = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">object</span>>();
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> layerO <span style="color: blue;">in</span> layersJA)
{
<span style="color: blue;">var</span> layerJO = layerO <span style="color: blue;">as</span> <span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">object</span>>;
<span style="color: blue;">var</span> id = layerJO[<span style="color: #a31515;">"layerId"</span>].ToString();
<span style="color: blue;">if</span> (authorizedLayerSet.Contains(id))
{
updatedLayers.Add(layerJO);
}
}
jsonResObj[<span style="color: #a31515;">"layers"</span>] = updatedLayers.ToArray();
<span style="color: green;">// Return the filter response</span>
<span style="color: blue;">return</span> sr.Serialize(jsonResObj);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ignore)
{
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> SOAP interceptors
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleStringWebRequest ( <span style="color: #2b91af;">esriHttpMethod</span> httpMethod, <span style="color: blue;">string</span> requestURL,
<span style="color: blue;">string</span> queryString, <span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> requestData,
<span style="color: blue;">out</span> <span style="color: blue;">string</span> responseContentType, <span style="color: blue;">out</span> <span style="color: #2b91af;">esriWebResponseDataType</span> respDataType )
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleStringWebRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Layer Access SOI for HandleStringWebRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate OGC (WMS, WFC, WCS etc) requests here </span>
<span style="color: green;"> */</span>
<span style="color: #2b91af;">IWebRequestHandler</span> webRequestHandler = _restServiceSOI.FindRequestHandlerDelegate<<span style="color: #2b91af;">IWebRequestHandler</span>>();
<span style="color: blue;">if</span> (webRequestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">var</span> response = webRequestHandler.HandleStringWebRequest(
httpMethod, requestURL, queryString, Capabilities, requestData, <span style="color: blue;">out</span> responseContentType, <span style="color: blue;">out</span> respDataType);
<span style="color: blue;">return</span> response;
}
responseContentType = <span style="color: blue;">null</span>;
respDataType = <span style="color: #2b91af;">esriWebResponseDataType</span>.esriWRDTPayload;
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleBinaryRequest ( <span style="color: blue;">ref</span> <span style="color: blue;">byte</span>[] request )
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleBinaryRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Layer Access SOI for HandleBinaryRequest"</span>);
<span style="color: green;">/*</span>
<span style="color: green;"> * Add code to manipulate Binary requests from desktop here</span>
<span style="color: green;"> */</span>
<span style="color: green;">// Generate a set of authorized layers for the user</span>
<span style="color: blue;">var</span> authorizedLayerSet = GetAuthorizedLayers(_soapServiceSOI);
<span style="color: #2b91af;">IMessage</span> requestMessage = <span style="color: #2b91af;">SoapServiceSOI</span>.ConvertBinaryRequestToMessage(request);
<span style="color: #2b91af;">SoapBinaryRequest</span> filteredRequest = FilterSoapRequest(requestMessage, <span style="color: #2b91af;">SoapRequestMode</span>.Binary, authorizedLayerSet) <span style="color: blue;">as</span> <span style="color: #2b91af;">SoapBinaryRequest</span>;
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == filteredRequest)
{
filteredRequest = <span style="color: blue;">new</span> <span style="color: #2b91af;">SoapBinaryRequest</span> { Body = request };
}
<span style="color: #2b91af;">IRequestHandler</span> requestHandler = _restServiceSOI.FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">var</span> response = requestHandler.HandleBinaryRequest(filteredRequest.Body);
<span style="color: green;">// Perform filtering for GetServerInfoResponse</span>
<span style="color: green;">// Convert the XML request into a generic IMessage</span>
<span style="color: #2b91af;">IMessage</span> responseMessage = <span style="color: #2b91af;">SoapServiceSOI</span>.ConvertBinaryRequestToMessage(response);
<span style="color: green;">// Get operation name</span>
<span style="color: #2b91af;">String</span> name = responseMessage.Name;
<span style="color: blue;">if</span> (<span style="color: #a31515;">"GetServerInfoResponse"</span>.Equals(name, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: green;">// Intercept the response and perform filtering</span>
<span style="color: blue;">var</span> filteredResponse = FilterSoapRequest(responseMessage, <span style="color: #2b91af;">SoapRequestMode</span>.Binary, authorizedLayerSet) <span style="color: blue;">as</span> <span style="color: #2b91af;">SoapBinaryRequest</span>;
<span style="color: blue;">if</span> (filteredResponse != <span style="color: blue;">null</span>)
{
response = filteredResponse.Body;
}
}
<span style="color: blue;">return</span> response;
}
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleBinaryRequest2 ( <span style="color: blue;">string</span> Capabilities, <span style="color: blue;">ref</span> <span style="color: blue;">byte</span>[] request )
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleBinaryRequest2()"</span>,
200, <span style="color: #a31515;">"Request received in Layer Access SOI for HandleBinaryRequest2"</span>);
<span style="color: #2b91af;">IMessage</span> requestMessage = <span style="color: #2b91af;">SoapServiceSOI</span>.ConvertBinaryRequestToMessage(request);
<span style="color: blue;">var</span> authorizedLayerSet = GetAuthorizedLayers(_soapServiceSOI);
<span style="color: #2b91af;">SoapBinaryRequest</span> filteredRequest = FilterSoapRequest(requestMessage, <span style="color: #2b91af;">SoapRequestMode</span>.Binary, authorizedLayerSet) <span style="color: blue;">as</span> <span style="color: #2b91af;">SoapBinaryRequest</span>;
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == filteredRequest)
{
filteredRequest = <span style="color: blue;">new</span> <span style="color: #2b91af;">SoapBinaryRequest</span> { Body = request };
}
<span style="color: #2b91af;">IRequestHandler2</span> requestHandler = _restServiceSOI.FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler2</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">var</span> response = requestHandler.HandleBinaryRequest2(Capabilities, filteredRequest.Body);
<span style="color: green;">// Perform filtering for GetServerInfoResponse</span>
<span style="color: green;">// Convert the XML request into a generic IMessage</span>
<span style="color: #2b91af;">IMessage</span> responseMessage = <span style="color: #2b91af;">SoapServiceSOI</span>.ConvertBinaryRequestToMessage(response);
<span style="color: green;">// Get operation name</span>
<span style="color: #2b91af;">String</span> name = responseMessage.Name;
<span style="color: blue;">if</span> (<span style="color: #a31515;">"GetServerInfoResponse"</span>.Equals(name, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: green;">// Intercept the response and perform filtering</span>
<span style="color: blue;">var</span> filteredResponse = FilterSoapRequest(responseMessage, <span style="color: #2b91af;">SoapRequestMode</span>.Binary, authorizedLayerSet) <span style="color: blue;">as</span> <span style="color: #2b91af;">SoapBinaryRequest</span>;
<span style="color: blue;">if</span> (filteredResponse != <span style="color: blue;">null</span>)
{
response = filteredResponse.Body;
}
}
<span style="color: blue;">return</span> response;
}
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> HandleStringRequest ( <span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> request )
{
_serverLog.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoStandard, _soiName + <span style="color: #a31515;">".HandleStringRequest()"</span>,
200, <span style="color: #a31515;">"Request received in Layer Access SOI for HandleStringRequest"</span>);
<span style="color: green;">// Convert the XML request into a generic IMessage</span>
<span style="color: #2b91af;">IMessage</span> requestMessage = <span style="color: #2b91af;">SoapServiceSOI</span>.ConvertStringRequestToMessage(request);
<span style="color: green;">// Generate a set of authorized layers for the user</span>
<span style="color: blue;">var</span> authorizedLayerSet = GetAuthorizedLayers(_soapServiceSOI);
<span style="color: green;">// Intercept the request and perform filtering</span>
<span style="color: blue;">var</span> filteredRequest = FilterSoapRequest(requestMessage, <span style="color: #2b91af;">SoapRequestMode</span>.Xml, authorizedLayerSet) <span style="color: blue;">as</span> <span style="color: #2b91af;">SoapStringRequest</span>;
<span style="color: blue;">if</span> (filteredRequest == <span style="color: blue;">null</span>)
{
filteredRequest = <span style="color: blue;">new</span> <span style="color: #2b91af;">SoapStringRequest</span> { Body = request };
}
<span style="color: #2b91af;">IRequestHandler</span> requestHandler = _restServiceSOI.FindRequestHandlerDelegate<<span style="color: #2b91af;">IRequestHandler</span>>();
<span style="color: blue;">if</span> (requestHandler != <span style="color: blue;">null</span>)
{
<span style="color: blue;">var</span> response = requestHandler.HandleStringRequest(Capabilities, filteredRequest.Body);
<span style="color: green;">// Perform filtering for GetServerInfoResponse</span>
<span style="color: green;">// Convert the XML request into a generic IMessage</span>
<span style="color: #2b91af;">IMessage</span> responseMessage = <span style="color: #2b91af;">SoapServiceSOI</span>.ConvertStringRequestToMessage(response);
<span style="color: green;">// Get operation name</span>
<span style="color: #2b91af;">String</span> name = responseMessage.Name;
<span style="color: blue;">if</span> (<span style="color: #a31515;">"GetServerInfoResponse"</span>.Equals(name, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: green;">// Intercept the response and perform filtering</span>
<span style="color: blue;">var</span> filteredResponse = FilterSoapRequest(responseMessage, <span style="color: #2b91af;">SoapRequestMode</span>.Xml, authorizedLayerSet) <span style="color: blue;">as</span> <span style="color: #2b91af;">SoapStringRequest</span>;
<span style="color: blue;">if</span> (filteredResponse != <span style="color: blue;">null</span>)
{
response = filteredResponse.Body;
}
}
<span style="color: blue;">return</span> response;
}
<span style="color: green;">//Insert error response here.</span>
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"inRequest"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"mode"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">SoapRequest</span> FilterSoapRequest ( <span style="color: #2b91af;">IMessage</span> inRequest, <span style="color: #2b91af;">SoapRequestMode</span> mode, <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayerSet )
{
<span style="color: green;">// Get operation name</span>
<span style="color: #2b91af;">String</span> name = inRequest.Name;
<span style="color: green;">// Apply filter only on those operations we care about</span>
<span style="color: blue;">var</span> nameInLowerCase = name.ToLower();
<span style="color: blue;">switch</span> (nameInLowerCase)
{
<span style="color: blue;">case</span> <span style="color: #a31515;">"find"</span>:
inRequest = FilterLayerIds(inRequest, mode, authorizedLayerSet);
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #a31515;">"exportmapimage"</span>:
inRequest = FilterMapDescription(inRequest, mode, authorizedLayerSet);
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #a31515;">"identify"</span>:
inRequest = FilterLayerIds(inRequest, mode, authorizedLayerSet);
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #a31515;">"getlegendinfo"</span>:
inRequest = FilterLayerIds(inRequest, mode, authorizedLayerSet);
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #a31515;">"getserverinforesponse"</span>:
inRequest = FilterGetServerInfoResponse(inRequest, mode, authorizedLayerSet);
<span style="color: blue;">break</span>;
}
<span style="color: blue;">return</span> <span style="color: #2b91af;">SoapRequestFactory</span>.Create(mode, inRequest);
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"inRequest"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"mode"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"authorizedLayerSet"</span><span style="color: grey;">></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IMessage</span> FilterLayerIds ( <span style="color: #2b91af;">IMessage</span> inRequest, <span style="color: #2b91af;">SoapRequestMode</span> mode, <span style="color: #2b91af;">HashSet</span><<span style="color: #2b91af;">String</span>> authorizedLayerSet )
{
<span style="color: green;">// 1. Find the index of the layers parameter</span>
<span style="color: green;">// 2. Get the value for the interested parameter</span>
<span style="color: green;">// 3. Manipulate it</span>
<span style="color: green;">// 4. Put it back into IMessage</span>
<span style="color: blue;">int</span> idx = -1;
<span style="color: #2b91af;">IXMLSerializeData</span> inRequestData = inRequest.Parameters;
<span style="color: blue;">try</span>
{
idx = inRequestData.Find(<span style="color: #a31515;">"LayerIDs"</span>);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ignore)
{
}
<span style="color: #2b91af;">LongArray</span> layerIdInLA = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (idx >= 0)
{
<span style="color: green;">// Get all the requested layers</span>
layerIdInLA = (<span style="color: #2b91af;">LongArray</span>)inRequestData.GetObject(idx, inRequest.NamespaceURI, <span style="color: #a31515;">"ArrayOfInt"</span>);
<span style="color: green;">// Perform filtering based on access to different layers. </span>
<span style="color: green;">// Remove restricted ids in-place</span>
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = layerIdInLA.Count - 1; i >= 0; i--)
{
<span style="color: blue;">if</span> (!authorizedLayerSet.Contains(layerIdInLA.Element[i].ToString()))
{
layerIdInLA.Remove(i);
}
}
}
<span style="color: blue;">else</span> <span style="color: green;">//no LayerIDs specified, attaching authorized layer list instead</span>
{
layerIdInLA = <span style="color: blue;">new</span> <span style="color: #2b91af;">LongArrayClass</span>();
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> goodLayerId <span style="color: blue;">in</span> authorizedLayerSet)
{
layerIdInLA.Add(<span style="color: #2b91af;">Int32</span>.Parse(goodLayerId));
}
inRequestData.AddObject(<span style="color: #a31515;">"LayerIDs"</span>, layerIdInLA);
}
<span style="color: green;">// If binary request we dont have to create and copy in a new Message object</span>
<span style="color: blue;">if</span> (mode == <span style="color: #2b91af;">SoapRequestMode</span>.Binary)
{
<span style="color: blue;">return</span> inRequest;
}
<span style="color: green;">// Create new request message</span>
<span style="color: #2b91af;">IMessage</span> modifiedInRequest = _soapServiceSOI.CreateNewIMessage(inRequest);
<span style="color: #2b91af;">IXMLSerializeData</span> modifiedInRequestData = modifiedInRequest.Parameters;
<span style="color: green;">// Put all parameters back in IMessage</span>
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < inRequestData.Count; i++)
{
<span style="color: blue;">if</span> (_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i).Equals(<span style="color: #a31515;">"LayerIDs"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: green;">// Add the modified MapDescription</span>
_soapServiceSOI.AddObjectToXMLSerializeData(_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i),
layerIdInLA, _soapServiceSOI.GetSoapOperationParameterTypeName(inRequest.Name, i), modifiedInRequestData);
}
<span style="color: blue;">else</span>
{
<span style="color: green;">/*</span>
<span style="color: green;"> * Add other parameters as is. Here we are using the SOI helper to add and get parameters</span>
<span style="color: green;"> * because we don't care about the type we just want to copy from one IMessage object to</span>
<span style="color: green;"> * another.</span>
<span style="color: green;"> */</span>
_soapServiceSOI.AddObjectToXMLSerializeData(
_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i),
_soapServiceSOI.GetObjectFromXMLSerializeData(i, inRequest.NamespaceURI,
_soapServiceSOI.GetSoapOperationParameterTypeName(inRequest.Name, i), inRequestData),
_soapServiceSOI.GetSoapOperationParameterTypeName(inRequest.Name, i), modifiedInRequestData);
}
}
<span style="color: blue;">return</span> modifiedInRequest;
}
<span style="color: blue;">private</span> <span style="color: #2b91af;">IMessage</span> FilterMapDescription ( <span style="color: #2b91af;">IMessage</span> inRequest, <span style="color: #2b91af;">SoapRequestMode</span> mode, <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayerSet )
{
<span style="color: green;">// 1. Find the index of the MapDescription parameter</span>
<span style="color: green;">// 2. Get the value for the interested parameter</span>
<span style="color: green;">// 3. Manipulate it</span>
<span style="color: green;">// 4. Put it back into IMessage</span>
<span style="color: green;">// Get the parameters out from the request object</span>
<span style="color: blue;">int</span> idx = -1;
<span style="color: #2b91af;">IXMLSerializeData</span> inRequestData = inRequest.Parameters;
idx = inRequestData.Find(<span style="color: #a31515;">"MapDescription"</span>);
<span style="color: #2b91af;">MapDescription</span> md =
(<span style="color: #2b91af;">MapDescription</span>)inRequestData.GetObject(idx, inRequest.NamespaceURI,
_soapServiceSOI.GetSoapOperationParameterTypeName(inRequest.Name, idx));
<span style="color: green;">// Manipulate the MapDescription to perform layer level security</span>
<span style="color: #2b91af;">ILayerDescriptions</span> lds = md.LayerDescriptions;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < lds.Count; i++)
{
<span style="color: #2b91af;">ILayerDescription</span> ld = lds.Element[i];
<span style="color: blue;">if</span> (!authorizedLayerSet.Contains(ld.ID.ToString()))
{
ld.Visible = <span style="color: blue;">false</span>;
}
}
<span style="color: green;">// If binary request we dont have to create and copy in a new Message object</span>
<span style="color: blue;">if</span> (mode == <span style="color: #2b91af;">SoapRequestMode</span>.Binary)
{
<span style="color: blue;">return</span> inRequest;
}
<span style="color: green;">// Create new request message</span>
<span style="color: #2b91af;">IMessage</span> modifiedInRequest = _soapServiceSOI.CreateNewIMessage(inRequest);
<span style="color: #2b91af;">IXMLSerializeData</span> modifiedInRequestData = modifiedInRequest.Parameters;
<span style="color: green;">// Put all parameters back in IMessage</span>
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < inRequestData.Count; i++)
{
<span style="color: blue;">if</span> (_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i).Equals(<span style="color: #a31515;">"MapDescription"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: green;">// Add the modified MapDescription</span>
modifiedInRequestData.AddObject(_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i), md);
}
<span style="color: blue;">else</span>
{
<span style="color: green;">/*</span>
<span style="color: green;"> * Add other parameters as is. Here we are using the SOI helper to add and get parameters</span>
<span style="color: green;"> * because we don't care about the type we just want to copy from one IMessage object to</span>
<span style="color: green;"> * another.</span>
<span style="color: green;"> */</span>
modifiedInRequestData.AddObject(
_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i),
inRequestData.GetObject(i, inRequest.NamespaceURI,
_soapServiceSOI.GetSoapOperationParameterTypeName(inRequest.Name, i)));
}
}
<span style="color: blue;">return</span> modifiedInRequest;
}
<span style="color: blue;">private</span> <span style="color: #2b91af;">IMessage</span> FilterGetServerInfoResponse ( <span style="color: #2b91af;">IMessage</span> inRequest, <span style="color: #2b91af;">SoapRequestMode</span> mode, <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> authorizedLayerSet )
{
<span style="color: blue;">int</span> idx = -1;
<span style="color: #2b91af;">IXMLSerializeData</span> inRequestData = inRequest.Parameters;
idx = inRequestData.Find(<span style="color: #a31515;">"Result"</span>);
<span style="color: green;">// Get MapServerInfo</span>
<span style="color: #2b91af;">MapServerInfo</span> mapServerInfo = (<span style="color: #2b91af;">MapServerInfo</span>)inRequestData.GetObject(idx, inRequest.NamespaceURI,
<span style="color: #a31515;">"MapServerInfo"</span>);
<span style="color: green;">// Perform filtering based on access to different layers</span>
<span style="color: #2b91af;">IMapLayerInfos</span> layerInfos = mapServerInfo.MapLayerInfos;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = layerInfos.Count - 1; i >= 0; i--)
{
<span style="color: blue;">if</span> (!authorizedLayerSet.Contains(layerInfos.Element[i].ID.ToString()))
{
layerInfos.Remove(i);
}
}
<span style="color: #2b91af;">IMapDescription</span> mapDescription = mapServerInfo.DefaultMapDescription;
<span style="color: #2b91af;">ILayerDescriptions</span> lds = mapDescription.LayerDescriptions;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = lds.Count - 1; i >= 0; i--)
{
<span style="color: blue;">if</span> (!authorizedLayerSet.Contains(lds.Element[i].ID.ToString()))
{
lds.Remove(i);
}
}
<span style="color: green;">// If binary request we don't have to create and copy in a new Message object</span>
<span style="color: blue;">if</span> (mode == <span style="color: #2b91af;">SoapRequestMode</span>.Binary)
{
<span style="color: blue;">return</span> inRequest;
}
<span style="color: green;">// Create new request message</span>
<span style="color: #2b91af;">IMessage</span> modifiedInRequest = _soapServiceSOI.CreateNewIMessage(inRequest);
<span style="color: #2b91af;">IXMLSerializeData</span> modifiedInRequestData = modifiedInRequest.Parameters;
<span style="color: green;">// Put all parameters back in IMessage</span>
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < inRequestData.Count; i++)
{
<span style="color: blue;">if</span> (_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i).Equals(<span style="color: #a31515;">"Result"</span>, <span style="color: #2b91af;">StringComparison</span>.CurrentCultureIgnoreCase))
{
<span style="color: green;">// Add the modified MapDescription</span>
modifiedInRequestData.AddObject(_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i), mapServerInfo);
}
<span style="color: blue;">else</span>
{
<span style="color: green;">/*</span>
<span style="color: green;"> * Add other parameters as is. Here we are using the SOI helper to add and get parameters</span>
<span style="color: green;"> * because we don't care about the type we just want to copy from one IMessage object to</span>
<span style="color: green;"> * another.</span>
<span style="color: green;"> */</span>
modifiedInRequestData.AddObject(
_soapServiceSOI.GetSoapOperationParameterName(inRequest.Name, i),
inRequestData.GetObject(i, inRequest.NamespaceURI,
_soapServiceSOI.GetSoapOperationParameterTypeName(inRequest.Name, i)));
}
}
<span style="color: blue;">return</span> modifiedInRequest;
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> Utility code
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Remove unauthorized layers from request. </span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestedLayers"</span><span style="color: grey;">></span><span style="color: green;">layer user is requesting information from</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"authorizedLayers"</span><span style="color: grey;">></span><span style="color: green;">layers user is authorized to fetch information from</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">String</span> RemoveUnauthorizedLayersFromRequestedLayers (
<span style="color: #2b91af;">String</span> requestedLayers, <span style="color: #2b91af;">HashSet</span><<span style="color: #2b91af;">String</span>> authorizedLayers )
{
<span style="color: blue;">if</span> (0 == authorizedLayers.Count)
<span style="color: blue;">return</span> <span style="color: #a31515;">"-1"</span>;
<span style="color: green;">// requested layers</span>
<span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">String</span>> requestedLayersList = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
requestedLayersList = requestedLayers.Split(<span style="color: blue;">new</span>[] { <span style="color: #a31515;">','</span> }).Select(e => e.Trim());
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ignore) { }
<span style="color: blue;">if</span> (authorizedLayers != <span style="color: blue;">null</span>)
{
<span style="color: blue;">var</span> filteredLayers = requestedLayersList.Where(e => authorizedLayers.Contains(e));
<span style="color: blue;">if</span> (!filteredLayers.Any())
<span style="color: blue;">return</span> <span style="color: #a31515;">"-1"</span>;
<span style="color: blue;">return</span> <span style="color: #2b91af;">String</span>.Join(<span style="color: #a31515;">","</span>, filteredLayers.ToArray());
}
<span style="color: blue;">return</span> <span style="color: #a31515;">"-1"</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Read permission information from disk</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"fileName"</span><span style="color: grey;">></span><span style="color: green;">path and name of the file to read permissions from</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">String</span>, <span style="color: #2b91af;">String</span>> ReadPermissionFile ( <span style="color: #2b91af;">String</span> fileName )
{
<span style="color: green;">// read the permissions file</span>
<span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">String</span>, <span style="color: #2b91af;">String</span>> permissionMap = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">String</span>, <span style="color: #2b91af;">String</span>>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">if</span> (!<span style="color: #2b91af;">File</span>.Exists(fileName))
<span style="color: blue;">return</span> permissionMap;
<span style="color: #2b91af;">String</span> jsonStr = <span style="color: #2b91af;">File</span>.ReadAllText(fileName);
<span style="color: blue;">var</span> json = <span style="color: blue;">new</span> ESRI.ArcGIS.SOESupport.<span style="color: #2b91af;">JsonObject</span>(jsonStr);
System.<span style="color: #2b91af;">Object</span>[] permissions = <span style="color: blue;">null</span>;
<span style="color: green;">// create a map of permissions</span>
<span style="color: green;">// read the permissions array</span>
<span style="color: blue;">if</span> (!json.TryGetArray(<span style="color: #a31515;">"permissions"</span>, <span style="color: blue;">out</span> permissions) || permissions == <span style="color: blue;">null</span>)
<span style="color: blue;">return</span> permissionMap;
<span style="color: green;">// add to map</span>
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> permsObj <span style="color: blue;">in</span> permissions)
{
ESRI.ArcGIS.SOESupport.<span style="color: #2b91af;">JsonObject</span> permsJO = permsObj <span style="color: blue;">as</span> ESRI.ArcGIS.SOESupport.<span style="color: #2b91af;">JsonObject</span>;
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == permsJO) <span style="color: blue;">continue</span>;
<span style="color: green;">// get the fqsn or service name</span>
<span style="color: #2b91af;">String</span> fqsn = <span style="color: blue;">string</span>.Empty;
permsJO.TryGetString(<span style="color: #a31515;">"fqsn"</span>, <span style="color: blue;">out</span> fqsn);
<span style="color: green;">// read the permission for that service</span>
System.<span style="color: #2b91af;">Object</span>[] permArray = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (!permsJO.TryGetArray(<span style="color: #a31515;">"permission"</span>, <span style="color: blue;">out</span> permArray) || permArray == <span style="color: blue;">null</span>)
<span style="color: blue;">continue</span>;
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> permObj <span style="color: blue;">in</span> permArray)
{
ESRI.ArcGIS.SOESupport.<span style="color: #2b91af;">JsonObject</span> permJO = permObj <span style="color: blue;">as</span> ESRI.ArcGIS.SOESupport.<span style="color: #2b91af;">JsonObject</span>;
<span style="color: #2b91af;">String</span> role = <span style="color: blue;">string</span>.Empty;
<span style="color: blue;">if</span> (!permJO.TryGetString(<span style="color: #a31515;">"role"</span>, <span style="color: blue;">out</span> role))
<span style="color: blue;">continue</span>;
<span style="color: #2b91af;">String</span> authorizedLayers = <span style="color: blue;">string</span>.Empty;
permJO.TryGetString(<span style="color: #a31515;">"authorizedLayers"</span>, <span style="color: blue;">out</span> authorizedLayers); <span style="color: green;">//may be empty or null</span>
permissionMap.Add(fqsn + <span style="color: #a31515;">"."</span> + role, authorizedLayers);
}
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ignore)
{
<span style="color: green;">//TODO error handling</span>
}
<span style="color: blue;">return</span> permissionMap;
}
<span style="color: blue;">private</span> <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>> GetAuthorizedLayers ( <span style="color: #2b91af;">ServiceSOIBase</span> soi )
{
<span style="color: blue;">var</span> userRoleSet = soi.GetRoleInformation(soi.ServerEnvironment.UserInfo);
<span style="color: #2b91af;">HashSet</span><<span style="color: #2b91af;">String</span>> authorizedLayerSet = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (<span style="color: blue;">null</span> == userRoleSet)
<span style="color: blue;">return</span> authorizedLayerSet;
<span style="color: green;">/*</span>
<span style="color: green;"> * Generate a set of authorized layers for the user</span>
<span style="color: green;"> */</span>
<span style="color: blue;">var</span> fullServiceName = _serverObject.ConfigurationName + <span style="color: #a31515;">"."</span> + _serverObject.TypeName;
<span style="color: blue;">var</span> removeSpacesRegEx = <span style="color: blue;">new</span> <span style="color: #2b91af;">Regex</span>(<span style="color: #a31515;">"\\s+"</span>);
<span style="color: blue;">var</span> authorizedRoles = userRoleSet.Where(role=>_servicePermissionMap.ContainsKey(fullServiceName + <span style="color: #a31515;">"."</span> + role));
<span style="color: blue;">var</span> authorizedLayerList = authorizedRoles.SelectMany(role => removeSpacesRegEx.
Replace(_servicePermissionMap[fullServiceName + <span style="color: #a31515;">"."</span> + role], <span style="color: #a31515;">""</span>).
Split(<span style="color: #a31515;">','</span>));
<span style="color: blue;">return</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">HashSet</span><<span style="color: blue;">string</span>>(authorizedLayerList);
}
<span style="color: blue;"> #endregion</span>
}</pre>
</div>
Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com3Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-43924292913543459382014-07-31T17:44:00.000+02:002018-09-28T16:53:21.828+02:00WebSocket con StreamLayerL'evoluzione delle applicazioni web ha anche determinato una crescente richiesta di comunicazioni in tempo reale: basti pensare ad applicazioni di chat, aggiornamenti in tempo reale, giochi online ecc. Il metodo più semplice fino ad ora utilizzato è quello del polling: ad intervalli prestabiliti il client chiede e il server risponde. Lo sviluppatore tramite script invia la richiesta e mediante la risposta del server verifica o meno la presenza delle informazioni richieste; la latenza però potrebbe non essere accettabile. La richiesta può essere tenuta anche più a lungo mantenendo il collegamento con il server (<a href="http://en.wikipedia.org/wiki/Comet_%28programming%29" target="_blank">long polling</a>). Questi ed altri metodi però presentano aspetti negativi quali l'inefficienza e la complessità.<br />
Il protocollo WebSocket risolve questi problemi perchè viene mantenuta una connessione TCP persistente, bidirezionale, full-duplex assicurata da un sistema di handshaking client-key ed un modello basato sull'origine; inoltre la trasmissione è mascherata per evitare <a href="http://tools.ietf.org/html/rfc6455#section-10.3" target="_blank">attacchi</a>. Per maggiori dettagli vedere <a href="http://tools.ietf.org/html/rfc6455" target="_blank">The WebSocket protocol</a> e <a href="http://www.w3.org/TR/websockets/" target="_blank">WebSocket API. </a><br />
Il framework 4.5 NET fornisce un'implementazione gestita del protocollo WebSocket mentre i moderni browser come Chrome, Firefox, Safari, Opera e IE10 supportano la specifica.<br />
Nativamente è supportato da Windows Server 2012 e Windows 8 con IIS8 e IIS8 Express. Con altre versioni di Windows si potrebbe utilizzare <a href="http://signalr.net/" target="_blank">SignalR</a> e <a href="http://socket.io/" target="_blank">Socket.IO</a> che hanno anche il grande vantaggio di supportare strategie di fallback (ad esempio browser client che non supportano WebSocket).<br />
Per installare WebSocket su Windows Server 2012:<br />
- Aprire <i>Server Manager;</i><br />
- cliccare su <i>Add Roles and Features;</i><br />
- selezionare <i>Role-based or Feature-based Installation</i> e poi cliccare su <i>Next;</i><br />
- selezionare il server (il server locale è selezionato di default) e poi cliccare su <i>Next;</i><br />
- espandere <i>Web Server (IIS)</i> in <i>Roles</i>, poi espandere <i>Web Server</i> e poi espandere <i>Application Development;</i><br />
- selezionare <i>WebSocket Protocol</i> e poi cliccare su<i> Next;</i><br />
- se non sono necessarie funzionalità aggiuntive cliccare su <i>Next;</i><br />
- cliccare su <i>Install;</i><br />
- quando l'installazione è completata chiudere il wizard.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYkIBUQOSut-Ohe2RUwxSL9BfPRl_k-REeJNwvkD076miavuyQSzOwMuBzIZccxEN9rNUiOoErIvZzcwLd8HdVetHpUSvE4jufWWQdJXstJkAjK6CjQBdyxk6KDEcGpSRzSRnoLaE5iokW/s1600/ws1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYkIBUQOSut-Ohe2RUwxSL9BfPRl_k-REeJNwvkD076miavuyQSzOwMuBzIZccxEN9rNUiOoErIvZzcwLd8HdVetHpUSvE4jufWWQdJXstJkAjK6CjQBdyxk6KDEcGpSRzSRnoLaE5iokW/s1600/ws1.png" /></a></div>
<br />
<br />
A questo punto l'IIS è abilitato a gestire il WebSocket.<br />
<br />
Ora ci creiamo un generico handler HTTP asincrono (disponibile con .NET 4.5) e ne deriviamo una classe specializzata. Registriamo il nuovo HTTP handler nel web.config dell'applicazione e ci creiamo una pagina javascript di test utilizzando le API Esri Javascript. Nello specifico possiamo utilizzare la classe <a href="https://developers.arcgis.com/javascript/jsapi/streamlayer-amd.html" target="_blank">StreamLayer</a> che permette di visualizzare <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/#/Feature_object/02r3000000n8000000/" target="_blank">feature</a> in real time da <a href="http://www.esri.com/software/arcgis/arcgisserver/extensions/geoevent-extension" target="_blank">GEP</a> ma anche da un WebSocket che fornisce <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/#/Feature_object/02r3000000n8000000/" target="_blank">feature in formato Esri JSON</a>.<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> StreamLayerDemo
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Diagnostics;
<span style="color: blue;">using</span> System.Diagnostics.CodeAnalysis;
<span style="color: blue;">using</span> System.Net.WebSockets;
<span style="color: blue;">using</span> System.Text;
<span style="color: blue;">using</span> System.Threading;
<span style="color: blue;">using</span> System.Threading.Tasks;
<span style="color: blue;">using</span> System.Web;
<span style="color: blue;">using</span> System.Web.WebSockets;
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.DocumentationRules"</span>, <span style="color: #a31515;">"SA1600:ElementsMustBeDocumented"</span>, Justification = <span style="color: #a31515;">"Demo code"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">abstract</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">WebSocketAsyncHandler</span> : <span style="color: #2b91af;">HttpTaskAsyncHandler</span>
{
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Gets a value indicating whether this handler can be reused for another request.</span>
<span style="color: grey;">///</span><span style="color: green;"> Should return false in case your Managed Handler cannot be reused for another request, or true otherwise.</span>
<span style="color: grey;">///</span><span style="color: green;"> Usually this would be false in case you have some state information preserved per request.</span>
<span style="color: grey;">///</span><span style="color: green;"> You will need to configure this handler in the Web.config file of your </span>
<span style="color: grey;">///</span><span style="color: green;"> web and register it with IIS before being able to use it. For more information</span>
<span style="color: grey;">///</span><span style="color: green;"> see the following link: </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"http://go.microsoft.com/?linkid=8101007"</span><span style="color: grey;"> /></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">bool</span> IsReusable
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: blue;">private</span> <span style="color: #2b91af;">WebSocket</span> Socket { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">async</span> <span style="color: #2b91af;">Task</span> ProcessRequestAsync(<span style="color: #2b91af;">HttpContext</span> httpContext)
{
<span style="color: blue;">await</span> <span style="color: #2b91af;">Task</span>.Run(() =>
{
<span style="color: blue;">if</span> (httpContext.IsWebSocketRequest)
{
httpContext.AcceptWebSocketRequest(<span style="color: blue;">async</span> <span style="color: blue;">delegate</span>(<span style="color: #2b91af;">AspNetWebSocketContext</span> context)
{
<span style="color: blue;">this</span>.Socket = context.WebSocket;
<span style="color: blue;">while</span> (<span style="color: blue;">this</span>.Socket != <span style="color: blue;">null</span> || <span style="color: blue;">this</span>.Socket.State != <span style="color: #2b91af;">WebSocketState</span>.Closed)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">switch</span> (<span style="color: blue;">this</span>.Socket.State)
{
<span style="color: blue;">case</span> <span style="color: #2b91af;">WebSocketState</span>.Connecting:
<span style="color: blue;">this</span>.OnConnecting();
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #2b91af;">WebSocketState</span>.Open:
<span style="color: blue;">this</span>.OnOpen();
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #2b91af;">WebSocketState</span>.CloseSent:
<span style="color: blue;">this</span>.OnClosing(<span style="color: blue;">false</span>, <span style="color: blue;">string</span>.Empty);
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #2b91af;">WebSocketState</span>.CloseReceived:
<span style="color: blue;">this</span>.OnClosing(<span style="color: blue;">true</span>, <span style="color: blue;">string</span>.Empty);
<span style="color: blue;">break</span>;
}
<span style="color: #2b91af;">ArraySegment</span><<span style="color: blue;">byte</span>> buffer = <span style="color: blue;">new</span> <span style="color: #2b91af;">ArraySegment</span><<span style="color: blue;">byte</span>>(<span style="color: blue;">new</span> <span style="color: blue;">byte</span>[1024]);
<span style="color: #2b91af;">WebSocketReceiveResult</span> receiveResult = <span style="color: blue;">await</span> <span style="color: blue;">this</span>.Socket.ReceiveAsync(buffer, <span style="color: #2b91af;">CancellationToken</span>.None);
<span style="color: blue;">switch</span> (receiveResult.MessageType)
{
<span style="color: blue;">case</span> <span style="color: #2b91af;">WebSocketMessageType</span>.Text:
<span style="color: blue;">string</span> message = <span style="color: #2b91af;">Encoding</span>.UTF8.GetString(buffer.Array, 0, receiveResult.Count);
<span style="color: blue;">this</span>.OnMessageReceived(message);
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #2b91af;">WebSocketMessageType</span>.Binary:
<span style="color: blue;">this</span>.OnMessageReceived(buffer.Array);
<span style="color: blue;">break</span>;
<span style="color: blue;">case</span> <span style="color: #2b91af;">WebSocketMessageType</span>.Close:
<span style="color: blue;">this</span>.OnClosing(<span style="color: blue;">true</span>, receiveResult.CloseStatusDescription);
<span style="color: blue;">break</span>;
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ex)
{
<span style="color: blue;">this</span>.OnError(ex);
}
}
});
}
});
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnConnecting()
{
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnOpen()
{
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnMessageReceived(<span style="color: blue;">string</span> message)
{
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnMessageReceived(<span style="color: blue;">byte</span>[] bytes)
{
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnClosing(<span style="color: blue;">bool</span> isClientRequest, <span style="color: blue;">string</span> message)
{
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnClosed()
{
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnError(<span style="color: #2b91af;">Exception</span> ex)
{
}
[<span style="color: #2b91af;">DebuggerStepThrough</span>]
<span style="color: blue;">protected</span> <span style="color: blue;">async</span> <span style="color: #2b91af;">Task</span> SendMessageAsync(<span style="color: blue;">byte</span>[] message)
{
<span style="color: blue;">await</span> <span style="color: blue;">this</span>.SendMessageAsync(message, <span style="color: #2b91af;">WebSocketMessageType</span>.Binary);
}
[<span style="color: #2b91af;">DebuggerStepThrough</span>]
<span style="color: blue;">protected</span> <span style="color: blue;">async</span> <span style="color: #2b91af;">Task</span> SendMessageAsync(<span style="color: blue;">string</span> message)
{
<span style="color: blue;">await</span> <span style="color: blue;">this</span>.SendMessageAsync(<span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(message), <span style="color: #2b91af;">WebSocketMessageType</span>.Text);
}
<span style="color: blue;">private</span> <span style="color: blue;">async</span> <span style="color: #2b91af;">Task</span> SendMessageAsync(<span style="color: blue;">byte</span>[] message, <span style="color: #2b91af;">WebSocketMessageType</span> messageType)
{
<span style="color: blue;">await</span> <span style="color: blue;">this</span>.Socket.SendAsync(
<span style="color: blue;">new</span> <span style="color: #2b91af;">ArraySegment</span><<span style="color: blue;">byte</span>>(message),
messageType,
<span style="color: blue;">true</span>,
<span style="color: #2b91af;">CancellationToken</span>.None);
}
}
}
</pre>
<br />
Deriviamo dalla classe astratta <a href="http://msdn.microsoft.com/en-us/library/system.web.httptaskasynchandler.aspx" target="_blank">HttpTaskAsyncHandler </a>ed eseguiamo l'override della proprietà <i>IsReusable</i> e del metodo <i>ProcessRequest</i> ed utilizzeremo async/await e la classe task perchè processiamo task asincroni.<br />
<br />
In questa classe ci limitiamo a memorizzare l'istanza del WebSocket con una proprietà, verificare se la richiesta http è una richiesta WebSocket (<i>IsWebSocketRequest</i>) e in funzione dello stato del WebSocket richiamare il corrispondente metodo virtuale. Inoltre implementiamo il codice per inviare messaggi al client. Il WebSocket permette di inviare e ricevere messaggi (testo e binario) in modalità asincrona. Questa classe generica permette di implementare la propria classe specializza handler WebSocket.<br />
<br />
Le implementazioni dei metodi virtuali saranno nella classe derivata:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> StreamLayerDemo
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Diagnostics.CodeAnalysis;
<span style="color: blue;">using</span> System.Threading.Tasks;
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.DocumentationRules"</span>, <span style="color: #a31515;">"SA1600:ElementsMustBeDocumented"</span>, Justification = <span style="color: #a31515;">"Demo code"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">StreamLayerWebSocketAsyncHandler</span> : <span style="color: #2b91af;">WebSocketAsyncHandler</span>
{
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnOpen()
{
<span style="color: #2b91af;">PointTicker</span>.DefaultInstance.Update += <span style="color: blue;">this</span>.PointTicker_Update;
<span style="color: blue;">base</span>.OnOpen();
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnClosing(<span style="color: blue;">bool</span> isClientRequest, <span style="color: blue;">string</span> message)
{
<span style="color: #2b91af;">PointTicker</span>.DefaultInstance.Update -= <span style="color: blue;">this</span>.PointTicker_Update;
<span style="color: blue;">base</span>.OnClosing(isClientRequest, message);
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnMessageReceived(<span style="color: blue;">string</span> message)
{
<span style="color: green;">// Assignment prevents warning "Because this call is not awaited...Consider applying the 'await' operator</span>
<span style="color: green;">// This is intentional => fire and forget</span>
<span style="color: green;">//Task task = this.SendMessageAsync("Your message is: " + message);</span>
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnError(<span style="color: #2b91af;">Exception</span> ex)
{
<span style="color: green;">// Assignment prevents warning "Because this call is not awaited...Consider applying the 'await' operator</span>
<span style="color: green;">// This is intentional => fire and forget</span>
<span style="color: blue;">var</span> task = <span style="color: blue;">this</span>.SendMessageAsync(<span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"Something exceptional happened: {0}"</span>, ex.Message));
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> PointTicker_Update(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">PointTickerEventArgs</span> e)
{
<span style="color: green;">// Assignment prevents warning "Because this call is not awaited...Consider applying the 'await' operator</span>
<span style="color: green;">// This is intentional => fire and forget</span>
<span style="color: blue;">var</span> task = <span style="color: blue;">this</span>.SendMessageAsync(e.Feature);
}
}
}</pre>
<br />
<br />
Per simulare l'invio di dati (in questo esempio dei <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000n1000000.htm#POINT" target="_blank">Point</a> casuali in un certo extent) utilizziamo una singola istanza di una classe che implementa un semplice <a href="http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx" target="_blank">Timer</a> che ogni 5 secondi invia una feature <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000n1000000.htm#POINT" target="_blank">Point</a> al client. I metodi Start e Stop della classe vengo richiamati negli eventi globali (global.asax.cs) Start e Stop dell'applicazione.<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> StreamLayerDemo
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Diagnostics.CodeAnalysis;
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.DocumentationRules"</span>, <span style="color: #a31515;">"SA1600:ElementsMustBeDocumented"</span>, Justification = <span style="color: #a31515;">"Demo code"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">Global</span> : System.Web.<span style="color: #2b91af;">HttpApplication</span>
{
<span style="color: blue;">protected</span> <span style="color: blue;">void</span> Application_Start(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: green;">// var hostFactory = new PointTickerHostFactory();</span>
<span style="color: green;">// var route = new ServiceRoute("PointTicker", hostFactory, typeof(PointTickerService));</span>
<span style="color: green;">// System.Web.Routing.RouteTable.Routes.Add(route);</span>
<span style="color: #2b91af;">PointTicker</span>.DefaultInstance.Start();
}
<span style="color: blue;">protected</span> <span style="color: blue;">void</span> Application_End(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: #2b91af;">PointTicker</span>.DefaultInstance.Stop();
}
}
}</pre>
<br />
<br />
Classe per simulare l'invio di dati al client:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> StreamLayerDemo
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Diagnostics.CodeAnalysis;
<span style="color: blue;">using</span> System.Timers;
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.DocumentationRules"</span>, <span style="color: #a31515;">"SA1600:ElementsMustBeDocumented"</span>, Justification = <span style="color: #a31515;">"Demo code"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">PointTicker</span>
{
<span style="color: blue;">private</span> <span style="color: blue;">const</span> <span style="color: blue;">int</span> TimerInterval = 5000;
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">object</span> lockField = <span style="color: blue;">new</span> <span style="color: blue;">object</span>();
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">PointTicker</span> defaultInstanceField;
<span style="color: blue;">private</span> PointTicker()
{
}
<span style="color: blue;">public</span> <span style="color: blue;">event</span> <span style="color: #2b91af;">EventHandler</span><<span style="color: #2b91af;">PointTickerEventArgs</span>> Update;
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">PointTicker</span> DefaultInstance
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">lock</span> (<span style="color: #2b91af;">PointTicker</span>.lockField)
{
<span style="color: blue;">if</span> (<span style="color: #2b91af;">PointTicker</span>.defaultInstanceField == <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">PointTicker</span>.defaultInstanceField = <span style="color: blue;">new</span> <span style="color: #2b91af;">PointTicker</span>();
<span style="color: #2b91af;">PointTicker</span>.defaultInstanceField.Initialize();
}
}
<span style="color: blue;">return</span> <span style="color: #2b91af;">PointTicker</span>.defaultInstanceField;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">Timer</span> Timer { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; }
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Start()
{
<span style="color: blue;">lock</span> (<span style="color: #2b91af;">PointTicker</span>.lockField)
{
<span style="color: blue;">if</span> (!<span style="color: #2b91af;">PointTicker</span>.Timer.Enabled)
{
<span style="color: #2b91af;">PointTicker</span>.Timer.Start();
}
}
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Stop()
{
<span style="color: blue;">lock</span> (<span style="color: #2b91af;">PointTicker</span>.lockField)
{
<span style="color: blue;">if</span> (<span style="color: #2b91af;">PointTicker</span>.Timer.Enabled)
{
<span style="color: #2b91af;">PointTicker</span>.Timer.Stop();
}
}
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> OnUpdate(<span style="color: blue;">string</span> feature)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.Update != <span style="color: blue;">null</span>)
{
<span style="color: blue;">this</span>.Update(
<span style="color: blue;">this</span>,
<span style="color: blue;">new</span> <span style="color: #2b91af;">PointTickerEventArgs</span>()
{
Feature = feature
});
}
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> Initialize()
{
<span style="color: #2b91af;">PointTicker</span>.Timer = <span style="color: blue;">new</span> <span style="color: #2b91af;">Timer</span>(<span style="color: #2b91af;">PointTicker</span>.TimerInterval);
<span style="color: #2b91af;">PointTicker</span>.Timer.Elapsed += <span style="color: blue;">this</span>.Timer_Elapsed;
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> Timer_Elapsed(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">ElapsedEventArgs</span> e)
{
<span style="color: #2b91af;">Random</span> random = <span style="color: blue;">new</span> <span style="color: #2b91af;">Random</span>();
<span style="color: blue;">string</span> feature = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"{{\"geometry\" : {{\"x\" : {0}, \"y\" : {1} }}, \"attributes\" : {{\"ObjectId\" : {2}, \"RouteID\" : 1, \"DateTimeStamp\" : {3} }}}}"</span>, random.NextDouble(8.40, 8.95).ToString(<span style="color: blue;">new</span> System.Globalization.<span style="color: #2b91af;">CultureInfo</span>(<span style="color: #a31515;">"en-US"</span>)), random.NextDouble(45.23, 45.85).ToString(<span style="color: blue;">new</span> System.Globalization.<span style="color: #2b91af;">CultureInfo</span>(<span style="color: #a31515;">"en-US"</span>)), random.Next(1, <span style="color: #2b91af;">Int32</span>.MaxValue), <span style="color: #2b91af;">DateTime</span>.Now.UnixTicks().ToString(<span style="color: blue;">new</span> System.Globalization.<span style="color: #2b91af;">CultureInfo</span>(<span style="color: #a31515;">"en-US"</span>)));
<span style="color: blue;">this</span>.OnUpdate(feature);
}
}
}</pre>
<br />
Ora registriamo l'handler nel web.config per indicare ad IIS di utilizzare questo handler quando richiamato.<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"><?</span><span style="color: #a31515;">xml</span><span style="color: blue;"> </span><span style="color: red;">version</span><span style="color: blue;">=</span>"<span style="color: blue;">1.0</span>"<span style="color: blue;">?></span>
<span style="color: blue;"><!--</span>
<span style="color: green;"> For more information on how to configure your ASP.NET application, please visit</span>
<span style="color: green;"> http://go.microsoft.com/fwlink/?LinkId=169433</span>
<span style="color: green;"> </span><span style="color: blue;">--></span>
<span style="color: blue;"><</span><span style="color: #a31515;">configuration</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">system.web</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">compilation</span><span style="color: blue;"> </span><span style="color: red;">debug</span><span style="color: blue;">=</span>"<span style="color: blue;">true</span>"<span style="color: blue;"> </span><span style="color: red;">targetFramework</span><span style="color: blue;">=</span>"<span style="color: blue;">4.5</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">httpRuntime</span><span style="color: blue;"> </span><span style="color: red;">targetFramework</span><span style="color: blue;">=</span>"<span style="color: blue;">4.5</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">system.web</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">system.webServer</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">handlers</span><span style="color: blue;">></span>
<span style="color: blue;"> <</span><span style="color: #a31515;">add</span><span style="color: blue;"> </span><span style="color: red;">name</span><span style="color: blue;">=</span>"<span style="color: blue;">StreamLayerWebSocketAsyncHandler</span>"<span style="color: blue;"> </span><span style="color: red;">verb</span><span style="color: blue;">=</span>"<span style="color: blue;">*</span>"<span style="color: blue;"> </span><span style="color: red;">path</span><span style="color: blue;">=</span>"<span style="color: blue;">wsStreamLayer</span>"<span style="color: blue;"> </span><span style="color: red;">type</span><span style="color: blue;">=</span>"<span style="color: blue;">StreamLayerDemo.StreamLayerWebSocketAsyncHandler, StreamLayerDemo</span>"<span style="color: blue;"> </span><span style="color: red;">resourceType</span><span style="color: blue;">=</span>"<span style="color: blue;">Unspecified</span>"<span style="color: blue;"> /></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">handlers</span><span style="color: blue;">></span>
<span style="color: blue;"> </</span><span style="color: #a31515;">system.webServer</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: #a31515;">configuration</span><span style="color: blue;">></span>
</pre>
<br />
Nel <i>Type</i> indicheremo la classe comprensiva del namespace affinchè IIS possa trovarla e nel path indicheremo il nome del WebSocket che utilizzeremo per chiamarlo (in questo caso l'ho chiamato wsStreamLayer):<br />
<div style="text-align: center;">
ws://<yourdomain>/<site:port>/wsStreamLayer</div>
<div style="text-align: center;">
<br /></div>
Per le creazione del collegamento, i WebSocket sfruttano il comando Http 'Upgrade' che indica al server che stiamo tentando di passare ad una connessione WebSocket<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitzYEtXtB-640KchAMKMQ-e2rEZ7dkE1sn8BcK-q_0hmueet7THAbWYwDhcTUN5kYwIxGEYeVlpinMkx4pWZfAFy9Dee-_iqJTMJzE9Pg_IGwx44W5q90dsmQWKUz2usnUxjHqdPX6Ohdr/s1600/ws2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitzYEtXtB-640KchAMKMQ-e2rEZ7dkE1sn8BcK-q_0hmueet7THAbWYwDhcTUN5kYwIxGEYeVlpinMkx4pWZfAFy9Dee-_iqJTMJzE9Pg_IGwx44W5q90dsmQWKUz2usnUxjHqdPX6Ohdr/s1600/ws2.png" /></a></div>
<br />
<br />
<br />
Come possiano notare da fiddler abbiamo anche <i>Origin</i>: questa origine è quella visionata dal server per capire da dove provengono i messaggi. Mentre <i>Sec-WebSocket-Key</i> è la chiave che compone la prima parte dell'handshake. E' generata in modo causale e codificata come stringa base64 di 16 byte. <i>Sec-WebSocket-Version</i> permette al server di rispondere con la versione del protocollo più adeguata alla versione supportata dal client.<br />
In risposta dal server <i>Sec-WebSocket-Accept</i> ha la chiave non codificata inviata dal client concatenata con 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 e codificata in SHA-1 e successivamente in base64.<br />
Inoltre come avviene per l'http è possibile effettuare la comunicazione WebSocket su ssl/tls tramite wss:<br />
<div style="text-align: center;">
wss://<yourdomain>/<site:port>/wsStreamLayer</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
A questo punto testiamo con la classe StreamLayer delle API js Esri:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
</div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"><</span><span style="color: maroon;">!doctype</span> <span style="color: red;">html</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">html</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">head</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">meta</span> <span style="color: red;">charset</span><span style="color: blue;">=</span><span style="color: blue;">"utf-8"</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">meta</span> <span style="color: red;">name</span><span style="color: blue;">=</span><span style="color: blue;">"viewport"</span> <span style="color: red;">content</span><span style="color: blue;">=</span><span style="color: blue;">"initial-scale=1, maximum-scale=1,user-scalable=no"</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">title</span><span style="color: blue;">></span>StreamLayer using ArcGIS API for JavaScript<span style="color: blue;"></</span><span style="color: maroon;">title</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">link</span> <span style="color: red;">rel</span><span style="color: blue;">=</span><span style="color: blue;">"stylesheet"</span> <span style="color: red;">href</span><span style="color: blue;">=</span><span style="color: blue;">"http://js.arcgis.com/3.10/js/dojo/dijit/themes/tundra/tundra.css"</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">link</span> <span style="color: red;">rel</span><span style="color: blue;">=</span><span style="color: blue;">"stylesheet"</span> <span style="color: red;">href</span><span style="color: blue;">=</span><span style="color: blue;">"http://js.arcgis.com/3.10/js/esri/css/esri.css"</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">style</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"text/css"</span><span style="color: blue;">></span>
<span style="color: maroon;">html</span>, <span style="color: maroon;">body</span> {
<span style="color: red;">height</span>: <span style="color: blue;">100%</span>;
<span style="color: red;">width</span>: <span style="color: blue;">100%</span>;
<span style="color: red;">margin</span>: <span style="color: blue;">0</span>;
<span style="color: red;">padding</span>: <span style="color: blue;">0</span>;
}
<span style="color: maroon;">body</span> {
<span style="color: red;">background-color</span>: <span style="color: blue;">#fff</span>;
<span style="color: red;">overflow</span>: <span style="color: blue;">hidden</span>;
<span style="color: red;">font-family</span>: <span style="color: blue;">sans-serif</span>;
}
<span style="color: maroon;">#map</span> {
<span style="color: red;">width</span>: <span style="color: blue;">100%</span>;
<span style="color: red;">height</span>: <span style="color: blue;">80%</span>;
}
<span style="color: blue;"></</span><span style="color: maroon;">style</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">script</span> <span style="color: red;">src</span><span style="color: blue;">=</span><span style="color: blue;">"http://js.arcgis.com/3.10/"</span><span style="color: blue;">></</span><span style="color: maroon;">script</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">head</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">body</span> <span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"tundra"</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">div</span> <span style="color: red;">id</span><span style="color: blue;">=</span><span style="color: blue;">"map"</span><span style="color: blue;">></</span><span style="color: maroon;">div</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">div</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">span</span><span style="color: blue;">></span>Enter websocket connection: <span style="color: blue;"></</span><span style="color: maroon;">span</span><span style="color: blue;">><</span><span style="color: maroon;">input</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"text"</span> <span style="color: red;">id</span><span style="color: blue;">=</span><span style="color: blue;">"txtWsUrl"</span> <span style="color: red;">value</span><span style="color: blue;">=</span><span style="color: blue;">"ws://localhost:55555/wsStreamLayer"</span> <span style="color: red;">style</span><span style="color: blue;">=</span><span style="color: blue;">"</span><span style="color: red;">width</span>: <span style="color: blue;">400px</span><span style="color: blue;">"</span> <span style="color: blue;">/><</span><span style="color: maroon;">br</span> <span style="color: blue;">/></span>
<span style="color: blue;"><</span><span style="color: maroon;">input</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"button"</span> <span style="color: red;">id</span><span style="color: blue;">=</span><span style="color: blue;">"cmdNewStream"</span> <span style="color: red;">value</span><span style="color: blue;">=</span><span style="color: blue;">"Make Stream Layer"</span> <span style="color: blue;">/></span>
<span style="color: blue;"><</span><span style="color: maroon;">input</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"button"</span> <span style="color: red;">id</span><span style="color: blue;">=</span><span style="color: blue;">"cmdDisconnect"</span> <span style="color: red;">value</span><span style="color: blue;">=</span><span style="color: blue;">"Disconnect Stream Layer"</span> <span style="color: blue;">/></span>
<span style="color: blue;"></</span><span style="color: maroon;">div</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">script</span><span style="color: blue;">></span>
<span style="color: blue;">var</span> curTime = <span style="color: blue;">new</span> Date();
<span style="color: blue;">var</span> curTimeStamp = Date.parse(curTime.toUTCString());
<span style="color: blue;">var</span> layerDefinition = {
<span style="color: #a31515;">"geometryType"</span>: <span style="color: #a31515;">"esriGeometryPoint"</span>,
<span style="color: #a31515;">"timeInfo"</span>: {
<span style="color: #a31515;">"startTimeField"</span>: <span style="color: #a31515;">"DateTimeStamp"</span>,
<span style="color: #a31515;">"endTimeField"</span>: <span style="color: blue;">null</span>,
<span style="color: #a31515;">"trackIdField"</span>: <span style="color: #a31515;">"RouteID"</span>,
<span style="color: #a31515;">"timeReference"</span>: <span style="color: blue;">null</span>,
<span style="color: #a31515;">"timeInterval"</span>: 1,
<span style="color: #a31515;">"timeIntervalUnits"</span>: <span style="color: #a31515;">"esriTimeUnitsMinutes"</span>,
<span style="color: #a31515;">"exportOptions"</span>: {
<span style="color: #a31515;">"useTime"</span>: <span style="color: blue;">true</span>,
<span style="color: #a31515;">"timeDataCumulative"</span>: <span style="color: blue;">false</span>,
<span style="color: #a31515;">"timeOffset"</span>: <span style="color: blue;">null</span>,
<span style="color: #a31515;">"timeOffsetUnits"</span>: <span style="color: blue;">null</span>
},
<span style="color: #a31515;">"hasLiveData"</span>: <span style="color: blue;">true</span>
},
<span style="color: #a31515;">"fields"</span>: [
{
name: <span style="color: #a31515;">"ObjectId"</span>,
type: <span style="color: #a31515;">"esriFieldTypeOID"</span>,
alias: <span style="color: #a31515;">"ObjectId"</span>
},
{
name: <span style="color: #a31515;">"DateTimeStamp"</span>,
type: <span style="color: #a31515;">"esriFieldTypeDate"</span>,
alias: <span style="color: #a31515;">"DateTimeStamp"</span>
},
{
name: <span style="color: #a31515;">"RouteID"</span>,
type: <span style="color: #a31515;">"esriFieldTypeInteger"</span>,
alias: <span style="color: #a31515;">"RouteID"</span>
}
]
};
<span style="color: blue;">var</span> map, featureCollection, streamLayer;
require([<span style="color: #a31515;">"esri/map"</span>,
<span style="color: #a31515;">"esri/TimeExtent"</span>,
<span style="color: #a31515;">"esri/layers/StreamLayer"</span>,
<span style="color: #a31515;">"esri/InfoTemplate"</span>,
<span style="color: #a31515;">"esri/symbols/SimpleMarkerSymbol"</span>,
<span style="color: #a31515;">"esri/symbols/SimpleLineSymbol"</span>,
<span style="color: #a31515;">"esri/renderers/SimpleRenderer"</span>,
<span style="color: #a31515;">"esri/renderers/TimeClassBreaksAger"</span>,
<span style="color: #a31515;">"esri/renderers/TemporalRenderer"</span>,
<span style="color: #a31515;">"esri/Color"</span>,
<span style="color: #a31515;">"dojo/dom"</span>,
<span style="color: #a31515;">"dojo/on"</span>,
<span style="color: #a31515;">"dojo/domReady!"</span>
], <span style="color: blue;">function</span> (Map, TimeExtent, StreamLayer, InfoTemplate, SimpleMarkerSymbol, SimpleLineSymbol, SimpleRenderer, TimeClassBreaksAger, TemporalRenderer, Color, dom, on) {
<span style="color: blue;">var</span> trackedBusses = {}, cnt = 0;
map = <span style="color: blue;">new</span> Map(<span style="color: #a31515;">"map"</span>, {
basemap: <span style="color: #a31515;">"gray"</span>,
center: [8.675, 45.54],
zoom: 10
});
<span style="color: green;">// event listeners for button clicks</span>
on(dom.byId(<span style="color: #a31515;">"cmdNewStream"</span>), <span style="color: #a31515;">"click"</span>, makeNewStreamLayer);
on(dom.byId(<span style="color: #a31515;">"cmdDisconnect"</span>), <span style="color: #a31515;">"click"</span>, disconnectStreamLayer);
<span style="color: blue;">function</span> makeStreamLayer() {
<span style="color: green;">//Make FeatureCollection to define layer without using url</span>
featureCollection = {
<span style="color: #a31515;">"layerDefinition"</span>: <span style="color: blue;">null</span>,
<span style="color: #a31515;">"featureSet"</span>: {
<span style="color: #a31515;">"features"</span>: [],
<span style="color: #a31515;">"geometryType"</span>: <span style="color: #a31515;">"esriGeometryPoint"</span>
}
};
featureCollection.layerDefinition = layerDefinition;
<span style="color: green;">// Instantiate StreamLayer</span>
<span style="color: green;">// 1. socketUrl is the url to the GeoEvent Processor web socket.</span>
<span style="color: green;">// 2. purgeOptions.displayCount is the maximum number of features the</span>
<span style="color: green;">// layer will display at one time</span>
<span style="color: green;">// 3. trackIdField is the name of the field that groups features</span>
<span style="color: blue;">var</span> layer = <span style="color: blue;">new</span> StreamLayer(featureCollection, {
socketUrl: txtWsUrl.value,
purgeOptions: { displayCount: 500 },
trackIdField: featureCollection.layerDefinition.timeInfo.trackIdField,
infoTemplate: <span style="color: blue;">new</span> InfoTemplate(<span style="color: #a31515;">"Route Id: ${RouteID}"</span>, <span style="color: #a31515;">"Timestamp: ${DateTimeStamp}"</span>)
});
console.log(<span style="color: #a31515;">"TrackID: "</span>, featureCollection.layerDefinition.timeInfo.trackIdField);
console.log(<span style="color: #a31515;">"TrackID: "</span>, layer.timeInfo.trackIdField);
<span style="color: green;">//Make renderer and apply it to StreamLayer</span>
<span style="color: blue;">var</span> renderer = makeRenderer();
layer.setRenderer(renderer);
<span style="color: green;">//Subscribe to onMessage event of StreamLayer so can adjust map time</span>
layer.on(<span style="color: #a31515;">"message"</span>, processMessage);
layer.on(<span style="color: #a31515;">"connect"</span>, connectevt);
layer.on(<span style="color: #a31515;">"error"</span>, errorevt);
<span style="color: blue;">return</span> layer;
}
<span style="color: blue;">function</span> connectevt() {
console.log(<span style="color: #a31515;">"Connesso"</span>);
}
<span style="color: blue;">function</span> errorevt() {
console.log(<span style="color: #a31515;">"error"</span>);
}
<span style="color: green;">// Process message that StreamLayer received.</span>
<span style="color: blue;">function</span> processMessage(message) {
<span style="color: blue;">if</span> (featureCollection.layerDefinition.timeInfo &&
featureCollection.layerDefinition.timeInfo.startTimeField) {
<span style="color: blue;">var</span> timestamp = message.attributes[featureCollection.layerDefinition.timeInfo.startTimeField];
<span style="color: blue;">if</span> (!map.timeExtent) {
map.setTimeExtent(<span style="color: blue;">new</span> esri.TimeExtent(<span style="color: blue;">new</span> Date(timestamp), <span style="color: blue;">new</span> Date(timestamp)));
console.log(<span style="color: #a31515;">"TIME EXTENT: "</span>, map.timeExtent);
} <span style="color: blue;">else</span> {
<span style="color: blue;">var</span> tsEnd = Date.parse(map.timeExtent.endTime.toString());
<span style="color: blue;">if</span> (timestamp > tsEnd) {
map.setTimeExtent(<span style="color: blue;">new</span> esri.TimeExtent(map.timeExtent.startTime, <span style="color: blue;">new</span> Date(timestamp)));
console.log(<span style="color: #a31515;">"TIME EXTENT: "</span>, map.timeExtent);
}
}
}
}
<span style="color: green;">// Make new StreamLayer and add it to map.</span>
<span style="color: blue;">function</span> makeNewStreamLayer() {
disconnectStreamLayer();
streamLayer = makeStreamLayer();
map.addLayer(streamLayer);
}
<span style="color: green;">// Disconnect StreamLayer from websocket and remove it from the map</span>
<span style="color: blue;">function</span> disconnectStreamLayer() {
<span style="color: blue;">if</span> (streamLayer) {
streamLayer.suspend();
streamLayer.disconnect();
streamLayer.clear();
map.removeLayer(streamLayer);
streamLayer = <span style="color: blue;">null</span>;
<span style="color: green;">//map.timeExtent = null;</span>
}
}
<span style="color: green;">// Make temporal renderer with latest observation renderer</span>
<span style="color: blue;">function</span> makeRenderer() {
<span style="color: blue;">var</span> obsRenderer = <span style="color: blue;">new</span> SimpleRenderer(
<span style="color: blue;">new</span> SimpleMarkerSymbol(<span style="color: #a31515;">"circle"</span>, 8,
<span style="color: blue;">new</span> SimpleLineSymbol(<span style="color: #a31515;">"solid"</span>,
<span style="color: blue;">new</span> Color([5, 112, 176, 0]), 1),
<span style="color: blue;">new</span> Color([5, 112, 176, 0.4])
));
<span style="color: blue;">var</span> latestObsRenderer = <span style="color: blue;">new</span> SimpleRenderer(
<span style="color: blue;">new</span> SimpleMarkerSymbol(<span style="color: #a31515;">"circle"</span>, 12,
<span style="color: blue;">new</span> SimpleLineSymbol(<span style="color: #a31515;">"solid"</span>,
<span style="color: blue;">new</span> Color([5, 112, 176, 0]), 1),
<span style="color: blue;">new</span> Color([5, 112, 176])
));
<span style="color: blue;">var</span> temporalRenderer = <span style="color: blue;">new</span> TemporalRenderer(obsRenderer, latestObsRenderer, <span style="color: blue;">null</span>, <span style="color: blue;">null</span>);
<span style="color: blue;">return</span> temporalRenderer;
}
});
<span style="color: blue;"></</span><span style="color: maroon;">script</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">body</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">html</span><span style="color: blue;">></span> </pre>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> </pre>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> </pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXRLD5ZotpfddlnCeqiTG6k88oJZdmV_yydCx8L28Xu0rUvhdrE1PdZJB2Iw5CwKpk8hfDgzeCSmWdYqhFZ95-2rXpx8aerWemdO2GjGxP82bbwLfsehOb36_aiTy0EDDYYep-baktmLRe/s1600/ws3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="588" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXRLD5ZotpfddlnCeqiTG6k88oJZdmV_yydCx8L28Xu0rUvhdrE1PdZJB2Iw5CwKpk8hfDgzeCSmWdYqhFZ95-2rXpx8aerWemdO2GjGxP82bbwLfsehOb36_aiTy0EDDYYep-baktmLRe/s1600/ws3.png" width="640" /></a></div>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> </pre>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> </pre>
Scaricare <a href="http://samples.sistemigis.it/Downloads/DemoStreamLayer.zip" target="_blank">qui </a>la soluzione.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-89559837843499780642014-05-31T18:31:00.000+02:002014-06-07T11:42:37.552+02:00TypeScriptOramai l'importanza di JavaScript nello sviluppo di applicazioni è ben noto a tutti. Il problema principale però rimane quando si sviluppano applicazioni di una certa complessità.<br />
La risposta di Microsoft è stata TypeScript che ha anche utilizzato il linguaggio in casa propria per progetti come Monaco, la versione web-based di Visual Studio.<br />
Il compilatore di TypeScript è implementato in linguaggio TypeScript ed è su <a href="http://typescript.codeplex.com/" target="_blank">CodePlex</a>. <br />
TypeScript è un superset di JavaScript, per la precisione un superset della sintassi ECMAScript 5 (ES5), cioè un linguaggio che estende JavaScript ma che produce in output codice JavasScript a seguito della compilazione. Essendo un superset, ogni programma JavaScript è anche un programma TypeScript. Inoltre la sintassi TypeScript include diverse caratteristiche proposte dell'ECMAScript 6 (ES6) che comprendono classi e moduli. Estendendo Javascript con tipi, classi, interfacce e moduli, si agevola lo sviluppo di applicazioni facilmente scalabili e si permette una maggiore produttività con i tool di sviluppo (refactoring, debugging, intellisense, tipi verificati staticamente ecc.). In sostanza tramite la type-safety ed una programmazione object-oriented si tutela lo sviluppo senza perdere i vantaggi di javascript, cross-platform in primis.<br />
TypeScript 1.0 è disponibile con l'<a href="http://www.microsoft.com/it-it/download/details.aspx?id=42666" target="_blank">update 2 di Visual Studio 2013</a> , come plug-in <a href="http://visualstudiogallery.msdn.microsoft.com/fa041d2d-5d77-494b-b0ba-8b4550792b4d" target="_blank">Visual Studio 2012</a> o anche come package di Node.js ( npm install -g typescript) ma è disponibile anche in altri IDE/Editor (Eclipse, JetBrains IDE, Sublime Text, Emacs, Vim ecc.).<br />
Sul sito <a href="http://www.typescriptlang.org/" target="_blank">typescriptlang.org</a> potete trovare tutte le risorse (tutorial, help, playground ecc.) riguardo a TypeScript.<br />
In Javascript si utilizzano molte librerie di terze parti (dojo, jquery ecc.) e per poterle utilizzare con TypeScript occorre innanzitutto dichiarare la libreria che si vuole utilizzare tramite il classico tag script. Per quel che riguarda lo sviluppo essa ha esclusivamente l'obiettivo di consentirci il normale funzionamento ma, dal punto di vista delle definizioni, non ha alcun effetto pratico.<br />
Per permettere al compilatore TypeScript di conoscere le definizioni, occorre innanzitutto procurarsi il file di definizione "libreria.d.ts" reperibile ad esempio su github. Esiste una collezione di definizioni molto estesa e aggiornata che è possibile trovare a questo indirizzo: <a href="https://github.com/borisyankov/DefinitelyTyped">https://github.com/borisyankov/DefinitelyTyped</a> o tramite nuget da console <i>Get-Package -Filter DefinitelyTyped -ListAvailable</i>. Il file di definizione permette di avere a disposizione l'intellisense ma soprattutto di conoscere i tipi validando il codice.<br />
Il file di definizione per ArcGIS API for JavaScript lo trovate nel repository Esri su github all'indirizzo: <a href="https://github.com/Esri/jsapi-resources/tree/master/typescript" target="_blank">https://github.com/Esri/jsapi-resources/tree/master/typescript</a><br />
<br />
Infine vediamo un semplicissimo esempio con ArcGIS API for JavaScript.<br />
<br />
Creiamo un nuovo progetto in Visual Studio 2013 utilizzando il template TypeScript:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjfiZA7fTTTijuxSf3XaYFx1S2jrAZaQJSyXhh9ZBm8i3_UkQ6ZyxeW-7lOlE7wHokvFIUyD61VdeoAcar9HwrtZIRaDSBTToOF6HwvdF_q7qb-ma7iRbiXT6c2bUuHLUgWNbhIGNDEUgQ/s1600/ts1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjfiZA7fTTTijuxSf3XaYFx1S2jrAZaQJSyXhh9ZBm8i3_UkQ6ZyxeW-7lOlE7wHokvFIUyD61VdeoAcar9HwrtZIRaDSBTToOF6HwvdF_q7qb-ma7iRbiXT6c2bUuHLUgWNbhIGNDEUgQ/s1600/ts1.png" height="440" width="640" /></a></div>
<br />
Importiamo il file di definizione esri.d.ts nella soluzione:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjk5_dpuIesgTrIYkDjoECbScgKd8VVDDCSPXHOHILXpKwbd0emss7wYnIe4POdYHZx0SP_lvtgAyFmAFAvxIffIHOa054R8yEWA2ASG5SC1RNrNH0BvVL_T98Gwp6wORHbcH8gMeaDXMo/s1600/ts11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjk5_dpuIesgTrIYkDjoECbScgKd8VVDDCSPXHOHILXpKwbd0emss7wYnIe4POdYHZx0SP_lvtgAyFmAFAvxIffIHOa054R8yEWA2ASG5SC1RNrNH0BvVL_T98Gwp6wORHbcH8gMeaDXMo/s1600/ts11.png" height="416" width="640" /></a></div>
<br />
Ora ci creiamo nel progetto un nuovo file TypeScript Point.ts (i file hanno estensione ts) e, ad esempio, estendiamo la classe Point di Esri. Le classi TypeScript supportano anche l'ereditarietà.<br />
Referenziamo il file di definizione esri.d.ts mediante una sintassi basata su un commento:<br />
<br />
/// <reference path="../esri.d.ts" /><br />
<br />
Ora aggiungiamo un metodo alla classe Point. Importiamo il modulo esterno di interesse assegnandoci un alias (AGSPoint) ed estendiamo la nostra classe (Point) con la parola chiave extends aggiungendo il metodo log() ed infine indichiamo che la classe potrà essere visibile all'esterno con export (può anche essere utilizzato anche per proprietà, metodi, tipi statici e anche semplici variabili)<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPMyHe5W-XyGT9YdlhLDVBn7JdUOy9p23lBq2FIeK01SCvZeDj2qpKP5AKkyuwI3QYEbgti_UyrD1AAsOqazWWe-GCe7KXSXWD5IzNeVLci6siIFZZVyz7eM2FU2PCvbfwFG8gD8tJ3pzq/s1600/ts12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPMyHe5W-XyGT9YdlhLDVBn7JdUOy9p23lBq2FIeK01SCvZeDj2qpKP5AKkyuwI3QYEbgti_UyrD1AAsOqazWWe-GCe7KXSXWD5IzNeVLci6siIFZZVyz7eM2FU2PCvbfwFG8gD8tJ3pzq/s1600/ts12.png" height="206" width="400" /></a></div>
<br />
e questo è il relativo js prodotto (Point.js):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhztFX_ZVQYUZZvaL3dbKFn6Ki-V3cDI97NUh17cX7qTlAb511t43Hau1uo1MNsCWtEC0nFnp77xAilxtPc3vUAvRojbWNpWFFEzdCdJCCuJYrhXOlQs0Mk0LD3BI5dtvkGaSwAJKa1Dyg-/s1600/ts18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhztFX_ZVQYUZZvaL3dbKFn6Ki-V3cDI97NUh17cX7qTlAb511t43Hau1uo1MNsCWtEC0nFnp77xAilxtPc3vUAvRojbWNpWFFEzdCdJCCuJYrhXOlQs0Mk0LD3BI5dtvkGaSwAJKa1Dyg-/s1600/ts18.png" height="331" width="640" /></a></div>
<br />
<br />
Ora aggiungiamo un altro file TypeScript (app.ts) dove utilizziamo, a titolo di esempio, la classe Point del modulo esterno Point.ts nel metodo di ingresso della pagine html per testarne il funzionamento:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf_ihha-mosinyey5O3sN8Xnfo2x7UyTYECZrnzKLV5CC9jDUgoSZ66N4nIxFWRa8Zqu2fP1D-2O0stMxX3UB53YIiR5YSHSHS88JXZY1_5mgbQzJO9A05ElqPxUQhN-HSim-7mtYYmrC2/s1600/ts13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf_ihha-mosinyey5O3sN8Xnfo2x7UyTYECZrnzKLV5CC9jDUgoSZ66N4nIxFWRa8Zqu2fP1D-2O0stMxX3UB53YIiR5YSHSHS88JXZY1_5mgbQzJO9A05ElqPxUQhN-HSim-7mtYYmrC2/s1600/ts13.png" height="165" width="400" /></a></div>
Importiamo il modulo esterno (Point.ts) ed utilizziamo la classe Point (in questo caso ho impostato l'alias p).<br />
Come possiamo notare quando scriviamo il codice ci viene in aiuto l'intellisense:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU0N6-9jpiuxf_aB67WaARHLYE96IDBtZuS0BOnC9BlaVj0IukepHV3zdILh5XUZwtWtQwlUrF6twuSYyJMAo8WgGrM6swK8fwzF9hBhn15_MpznFL2TEspvPM91_sG2g1nxhL3c68vase/s1600/ts14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU0N6-9jpiuxf_aB67WaARHLYE96IDBtZuS0BOnC9BlaVj0IukepHV3zdILh5XUZwtWtQwlUrF6twuSYyJMAo8WgGrM6swK8fwzF9hBhn15_MpznFL2TEspvPM91_sG2g1nxhL3c68vase/s1600/ts14.png" height="224" width="640" /></a></div>
<br />
e questa è la nostra pagina html che richiama la funzione in app.ts<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUl6oCmPX3gwd0TLx4QUukGa9YdQmBhSxNAuv-imAG6UZGTtNEw-jqxe3178LPoOrPSvd5fnkHrXsEM0kFxCt8iFEyVVbXzv_wEujHY-7k88Q9hl9IkxAUzovI42cwM8Cl92iRcp8KUNSa/s1600/ts15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUl6oCmPX3gwd0TLx4QUukGa9YdQmBhSxNAuv-imAG6UZGTtNEw-jqxe3178LPoOrPSvd5fnkHrXsEM0kFxCt8iFEyVVbXzv_wEujHY-7k88Q9hl9IkxAUzovI42cwM8Cl92iRcp8KUNSa/s1600/ts15.png" height="498" width="640" /></a></div>
<br />
<br />
Eseguiamo e verifichiamo dalla console del browser il risultato:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwYn3mIDS49WApKt3_L5GSKgT6d9tySLpgjoOjWhkXbosLiG2zO8owhhcdrp4za7p6_FOErjpP0hvUO2koTdkkScASTnpcpdRRJE6_UQIaoC3VhzXVOzem4CVWNrJNnMdEFWsQMnXTSOv-/s1600/ts16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwYn3mIDS49WApKt3_L5GSKgT6d9tySLpgjoOjWhkXbosLiG2zO8owhhcdrp4za7p6_FOErjpP0hvUO2koTdkkScASTnpcpdRRJE6_UQIaoC3VhzXVOzem4CVWNrJNnMdEFWsQMnXTSOv-/s1600/ts16.png" height="143" width="400" /></a></div>
<br />
e possiamo, come detto, andare in debug:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidJmdU5F-XuTtt3xtJrB6Fj_uCEpe8VbIaKxTug3utMokSM07Aq3FYVVdHfPMymj73sryGkI1des1sa_QUnBgtAzR5F1rFZgTEZLINDtjvbCYeOQDlZCb3BmPLr8IV266fzBt2imyWuf4G/s1600/ts17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidJmdU5F-XuTtt3xtJrB6Fj_uCEpe8VbIaKxTug3utMokSM07Aq3FYVVdHfPMymj73sryGkI1des1sa_QUnBgtAzR5F1rFZgTEZLINDtjvbCYeOQDlZCb3BmPLr8IV266fzBt2imyWuf4G/s1600/ts17.png" height="211" width="320" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-61207982658187200032014-02-28T16:07:00.000+01:002014-03-15T10:29:22.699+01:00Custom Identity store ASP.NETL'identity store è dove vengono gestiti gli utenti e i ruoli. ArcGIS Server ingloba un suo identity store pronto all'uso.<br />
Nell'admin rest di ArcGIS Server possiamo vedere la configurazione di default che imposta l'identity store integrato (built-in), nella sezione security -> config -> updateIdentityStore<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOcfQO1DsCLtgRz9wePQg3ZaLDWGNf-5vTdTeD6MiH5HXMVUrm0uIwUl1oD-flWZDzOR92FBKitSuUxUfIK6-QfgHZjbh0JUt1qwjF1pN3bsM0A3cijjt08D0qdq_-xnu9q5hW9mKp9OvV/s1600/CustomProvider1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOcfQO1DsCLtgRz9wePQg3ZaLDWGNf-5vTdTeD6MiH5HXMVUrm0uIwUl1oD-flWZDzOR92FBKitSuUxUfIK6-QfgHZjbh0JUt1qwjF1pN3bsM0A3cijjt08D0qdq_-xnu9q5hW9mKp9OvV/s1600/CustomProvider1.png" height="480" width="640" /></a></div>
Ma tra le varie possibilità ArcGIS Server permette anche di crearsi il proprio identity store. Difatti la nostra organizzazione potrebbe già gestire ad esempio un database con i propri utenti ed i ruoli ai quali appartengono gli utenti e quindi se dovessimo affidarci al built-in di ArcGIS Server avremmo una duplicazione di informazioni.<br />
ArcGIS Server fornisce il supporto per i provider ASP.NET Membership e Role.<br />
<br />
Per poter implementare i provider personalizzati occorre implementare i seguenti metodi:<br />
<br />
Membership provider:<br />
<ul>
<li>FindUsersByName</li>
<li>GetAllUsers</li>
<li>GetUser</li>
<li>ValidateUser</li>
</ul>
Role provider:<br />
<ul>
<li>GetAllRoles</li>
<li>GetRolesForUser</li>
<li>GetUsersInRole</li>
</ul>
A titolo di esempio ci creiamo il nostro database su SQL Server con le tre tabelle necessarie per poter memorizzare il minimo di informazione sul quale andremo a gestire i ruoli e gli utenti. Chiaramente nulla ci vieta di utilizzare qualsiasi database o store dove memorizzare le nostre informazioni visto che l'implementazione è a carico dello sviluppatore.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgMs9WLICUAYcJ770h3GVriMRPYwJcsYBCpLj3fqp0GgjoUJyhxB7h9H2lgKNkwotg1I8I4MIce611sFEjKYMnC1ENZOOcV7wASjF82pzgm67gHaV0yV-1Fhyphenhyphen5ogCAa0Qz4ikxrSsjpWQj/s1600/CustomProvider2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgMs9WLICUAYcJ770h3GVriMRPYwJcsYBCpLj3fqp0GgjoUJyhxB7h9H2lgKNkwotg1I8I4MIce611sFEjKYMnC1ENZOOcV7wASjF82pzgm67gHaV0yV-1Fhyphenhyphen5ogCAa0Qz4ikxrSsjpWQj/s1600/CustomProvider2.png" height="427" width="640" /></a></div>
In questo caso impostiamo anche le azioni di CASCATE sulle integrità referenziali così da eliminare automaticamente le associazioni ruoli-utenti quando si eliminano ruoli o utenti. Anche in questo caso è una scelta progettuale se si opta per forzare la cancellazione.<br />
<br />
A questo punto in Visual Studio ci creiamo una libreria utilizzando il framework 3.5.<br />
<br />
Ci creamo due classi: una che eredita dal MembershipProvider e che rappresenta il nostro Membership Provider ed un'altra che eredita da RoleProvider e che rappresenta il nostro Role Provider.<br />
<br />
Vediamo nel dettaglio il MembershipProvider. <br />
Il primo metodo che andiamo ad implementare è l'Initialize dove vengono passate le proprietà di configurazione del Membership Provider. A titolo esemplificativo impostiamo una proprietà dove indicare la stringa di connessione al database e una proprietà per indicare se desideriamo ricevere eventuali errori sull'event viewer di Windows o direttamente sulla pagina. Le proprietà successivamente verranno impostate in ArcGIS Server quando indicheremo il nostro custom provider.<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> initialize provider</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"name"</span><span style="color: grey;">></span><span style="color: green;">name provider</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"config"</span><span style="color: grey;">></span><span style="color: green;">properties in config</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> Initialize(<span style="color: blue;">string</span> name, System.Collections.Specialized.<span style="color: #2b91af;">NameValueCollection</span> config)
{
<span style="color: blue;">if</span> (config == <span style="color: blue;">null</span>)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"config"</span>);
}
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.IsNullOrEmpty(name))
{
name = <span style="color: blue;">string</span>.Format(<span style="color: #2b91af;">CultureInfo</span>.InvariantCulture, <span style="color: #a31515;">"{0}.{1}"</span>, <span style="color: blue;">this</span>.GetType().Namespace, <span style="color: blue;">this</span>.GetType().Name);
}
<span style="color: blue;">base</span>.Initialize(name, config);
<span style="color: blue;">this</span>.providerName = name;
<span style="color: blue;">string</span> connectionStringName = config[<span style="color: #a31515;">"connectionStringName"</span>];
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.IsNullOrEmpty(connectionStringName))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArcGisServerCustomProviderException</span>(<span style="color: #a31515;">"connectionStringName"</span>);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">this</span>.connectionString = connectionStringName;
}
<span style="color: blue;">this</span>.WriteExceptionsToEventLog = <span style="color: #2b91af;">Convert</span>.ToBoolean(<span style="color: #2b91af;">Helper</span>.GetConfigValue(config[<span style="color: #a31515;">"writeExceptionsToEventLog"</span>], <span style="color: #a31515;">"false"</span>), <span style="color: #2b91af;">CultureInfo</span>.InvariantCulture);
<span style="color: green;">// test for connection</span>
<span style="color: blue;">try</span>
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
connection.Open();
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArcGisServerCustomProviderException</span>(<span style="color: #a31515;">"Check your DB connection!"</span>);
}
}</pre>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> </pre>
Il secondo metodo che andiamo a riscrivere è il CreateUser che è quello che viene richiamato quando in ArcGIS Server Manager aggiungiamo un utente (pulsante New User):<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> create a user</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"username"</span><span style="color: grey;">></span><span style="color: green;">value of username</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"password"</span><span style="color: grey;">></span><span style="color: green;">value of password</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"email"</span><span style="color: grey;">></span><span style="color: green;">value email</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"passwordQuestion"</span><span style="color: grey;">></span><span style="color: green;">password Question</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"passwordAnswer"</span><span style="color: grey;">></span><span style="color: green;">password Answer</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"isApproved"</span><span style="color: grey;">></span><span style="color: green;">is Approved</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"providerUserKey"</span><span style="color: grey;">></span><span style="color: green;">provider User Key</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"status"</span><span style="color: grey;">></span><span style="color: green;">value of status</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">object MembershipUser</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: #2b91af;">MembershipUser</span> CreateUser(<span style="color: blue;">string</span> username, <span style="color: blue;">string</span> password, <span style="color: blue;">string</span> email, <span style="color: blue;">string</span> passwordQuestion, <span style="color: blue;">string</span> passwordAnswer, <span style="color: blue;">bool</span> isApproved, <span style="color: blue;">object</span> providerUserKey, <span style="color: blue;">out</span> <span style="color: #2b91af;">MembershipCreateStatus</span> status)
{
<span style="color: #2b91af;">MembershipUser</span> newUser = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
newUser = <span style="color: blue;">this</span>.GetUser(username, <span style="color: blue;">false</span>);
<span style="color: blue;">if</span> (newUser == <span style="color: blue;">null</span>)
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"INSERT INTO Users (Username, Password) VALUES (@UserName, @Password)"</span>, connection))
{
cmd.Parameters.Add(<span style="color: #a31515;">"@UserName"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = username;
cmd.Parameters.Add(<span style="color: #a31515;">"@Password"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = password;
connection.Open();
<span style="color: blue;">int</span> recordAdded = cmd.ExecuteNonQuery();
<span style="color: blue;">if</span> (recordAdded > 0)
{
status = <span style="color: #2b91af;">MembershipCreateStatus</span>.Success;
newUser = <span style="color: blue;">this</span>.GetUser(username);
}
<span style="color: blue;">else</span>
{
status = <span style="color: #2b91af;">MembershipCreateStatus</span>.UserRejected;
}
}
}
}
<span style="color: blue;">else</span>
{
status = <span style="color: #2b91af;">MembershipCreateStatus</span>.DuplicateUserName;
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
status = <span style="color: #2b91af;">MembershipCreateStatus</span>.ProviderError;
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerMembershipProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;">if</span> (status != <span style="color: #2b91af;">MembershipCreateStatus</span>.Success)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArcGisServerCustomProviderException</span>(<span style="color: #2b91af;">ArcGisServerMembershipProvider</span>.GetErrorMessage(status));
}
<span style="color: blue;">return</span> newUser;
}</pre>
<br />
<br />
Il metodo FindUsersByName serve ad ArcGIS Server per filtrare gli utenti con criterio parte-del-campo sul nome utente quindi in questo caso utilizzeremo un LIKE (casella di testo Find User) mentre il pageIndex e il pageSize è per la gestione del paging:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Find Users By Name</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"usernameToMatch"</span><span style="color: grey;">></span><span style="color: green;">username To Match</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"pageIndex"</span><span style="color: grey;">></span><span style="color: green;">page Index</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"pageSize"</span><span style="color: grey;">></span><span style="color: green;">page Size</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"totalRecords"</span><span style="color: grey;">></span><span style="color: green;">total Records</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">object MembershipUserCollection</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: #2b91af;">MembershipUserCollection</span> FindUsersByName(<span style="color: blue;">string</span> usernameToMatch, <span style="color: blue;">int</span> pageIndex, <span style="color: blue;">int</span> pageSize, <span style="color: blue;">out</span> <span style="color: blue;">int</span> totalRecords)
{
<span style="color: #2b91af;">MembershipUserCollection</span> users = <span style="color: blue;">new</span> <span style="color: #2b91af;">MembershipUserCollection</span>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"SELECT Count(*) FROM Users WHERE Username LIKE @Username"</span>, connection))
{
cmd.Parameters.Add(<span style="color: #a31515;">"@Username"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = <span style="color: blue;">string</span>.Format(<span style="color: #2b91af;">CultureInfo</span>.InvariantCulture, <span style="color: #a31515;">"%{0}%"</span>, usernameToMatch);
connection.Open();
totalRecords = (<span style="color: blue;">int</span>)cmd.ExecuteScalar();
<span style="color: blue;">if</span> (totalRecords <= 0)
{
<span style="color: blue;">return</span> users;
}
}
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"SELECT Id, Username FROM Users WHERE Username LIKE @Username ORDER BY Username ASC"</span>, connection))
{
cmd.Parameters.Add(<span style="color: #a31515;">"@Username"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = <span style="color: blue;">string</span>.Format(<span style="color: #2b91af;">CultureInfo</span>.InvariantCulture, <span style="color: #a31515;">"%{0}%"</span>, usernameToMatch);
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlDataReader</span> reader = cmd.ExecuteReader())
{
<span style="color: blue;">if</span> (reader.HasRows)
{
<span style="color: blue;">int</span> counter = 0;
<span style="color: blue;">int</span> startIndex = pageSize * pageIndex;
<span style="color: blue;">int</span> endIndex = startIndex + pageSize - 1;
<span style="color: blue;">while</span> (reader.Read())
{
<span style="color: blue;">if</span> (counter >= startIndex)
{
<span style="color: #2b91af;">MembershipUser</span> user = <span style="color: blue;">this</span>.GetUserByReader(reader);
users.Add(user);
}
<span style="color: blue;">if</span> (counter >= endIndex)
{
cmd.Cancel();
}
counter++;
}
}
}
}
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerMembershipProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ProviderException</span>(ExceptionMessage);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;">return</span> users;
}</pre>
<br />
Il metodo GetAllUsers è per visualizzare tutti gli utenti presenti. Anche in questo caso abbiamo la gestione del paging:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> get all users</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"pageIndex"</span><span style="color: grey;">></span><span style="color: green;">page Index</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"pageSize"</span><span style="color: grey;">></span><span style="color: green;">page Size</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"totalRecords"</span><span style="color: grey;">></span><span style="color: green;">total Records</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">objects MembershipUserCollection</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: #2b91af;">MembershipUserCollection</span> GetAllUsers(<span style="color: blue;">int</span> pageIndex, <span style="color: blue;">int</span> pageSize, <span style="color: blue;">out</span> <span style="color: blue;">int</span> totalRecords)
{
<span style="color: #2b91af;">MembershipUserCollection</span> users = <span style="color: blue;">new</span> <span style="color: #2b91af;">MembershipUserCollection</span>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"SELECT Count(*) FROM Users"</span>, connection))
{
connection.Open();
totalRecords = (<span style="color: blue;">int</span>)cmd.ExecuteScalar();
<span style="color: blue;">if</span> (totalRecords <= 0)
{
<span style="color: blue;">return</span> users;
}
}
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"SELECT Id, Username FROM Users ORDER BY Username"</span>, connection))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlDataReader</span> reader = cmd.ExecuteReader())
{
<span style="color: blue;">if</span> (reader.HasRows)
{
<span style="color: blue;">int</span> counter = 0;
<span style="color: blue;">int</span> startIndex = pageSize * pageIndex;
<span style="color: blue;">int</span> endIndex = startIndex + pageSize - 1;
<span style="color: blue;">while</span> (reader.Read())
{
<span style="color: blue;">if</span> (counter >= startIndex)
{
<span style="color: #2b91af;">MembershipUser</span> user = <span style="color: blue;">this</span>.GetUserByReader(reader);
users.Add(user);
}
<span style="color: blue;">if</span> (counter >= endIndex)
{
cmd.Cancel();
}
counter++;
}
}
}
}
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerMembershipProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ProviderException</span>(ExceptionMessage);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
totalRecords = users.Count;
<span style="color: blue;">return</span> users;
}</pre>
<br />
Il metodo DeleteUser elimina l'utente. In ArcGIS Server Manager viene richiamato quando si clicca sul pulsante di eliminazione dell'utente:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> delete user</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"username"</span><span style="color: grey;">></span><span style="color: green;">value of username</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"deleteAllRelatedData"</span><span style="color: grey;">></span><span style="color: green;">delete All Related Data</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">true is ok</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">bool</span> DeleteUser(<span style="color: blue;">string</span> username, <span style="color: blue;">bool</span> deleteAllRelatedData)
{
<span style="color: blue;">int</span> rowsAffected = 0;
<span style="color: blue;">try</span>
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"DELETE FROM Users WHERE Username = @Username"</span>, connection))
{
cmd.Parameters.Add(<span style="color: #a31515;">"@Username"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = username;
connection.Open();
rowsAffected = cmd.ExecuteNonQuery();
}
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerMembershipProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ProviderException</span>(ExceptionMessage);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;">return</span> rowsAffected > 0;
}</pre>
<br />
Il metodo GetUser restituisce l'utente una volta dato il suo username mentre il ValidateUser verifica se l'utente esiste. Per metodi che restituiscono gli oggetti della classe MembershipUser creeremo un oggetto fornendo al costruttore la username e il nome del provider mentre per gli altri argomenti forniremo dati fittizi o nulli poiché non gestiamo altre informazioni per l'utente (e-mail ecc.).<br />
Per tutti gli altri metodi che non andiamo a riscrivere gettiamo un'eccezione di tipo NotImplementedException:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Get Number Of Users Online</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">number of users online</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">int</span> GetNumberOfUsersOnline()
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">NotImplementedException</span>(<span style="color: blue;">string</span>.Format(<span style="color: #2b91af;">CultureInfo</span>.InvariantCulture, <span style="color: #a31515;">"Method not implemented: {0}"</span>, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name));
}
</pre>
<br />
Vediamo ora nel dettaglio il RoleProvider.<br />
Anche qui nell'Initialize come per il Membership Provider vengo passate le proprietà di configurazione che in questo caso d'esempio sono le stesse: stringa di connessione del database e notifica di errori nell'event viewer o direttamente nella pagina dell'ArcGIS Manager. Pertanto il metodo è analogo a quello del Membership Provider.<br />
<br />
Il metodo CreateRole crea il ruolo e viene richiamato quando in ArcGIS Server Manager si clicca sul pulsante New Role. Attenzione che il tipo di ruolo - cioè se User, Publisher o Administrator - è un'informazione che memorizza ArcGIS Server autonomamente.<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> create a role</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"roleName"</span><span style="color: grey;">></span><span style="color: green;">role name</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> CreateRole(<span style="color: blue;">string</span> roleName)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.RoleExists(roleName))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ProviderException</span>(<span style="color: #a31515;">"Role exists!"</span>);
}
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"INSERT INTO Roles (Rolename) VALUES (@Role)"</span>, connection))
{
cmd.Parameters.Add(<span style="color: #a31515;">"@Role"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = roleName;
connection.Open();
cmd.ExecuteNonQuery();
}
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerRoleProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
}</pre>
<br />
I metodi DeleteRole e GetAllRoles sono analoghi a quelli del Membership Provider e servono per eliminare un ruolo e listare tutti i ruoli presenti.<br />
<br />
I metodi GetRolesForUser e GetUsersInRole vengono utilizzati da ArcGIS Server Manager per visualizzare l'associazione tra utenti e ruoli dato l'utente o il ruolo.<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Get of roles for user</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"username"</span><span style="color: grey;">></span><span style="color: green;">name of user</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">list of roles</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">string</span>[] GetRolesForUser(<span style="color: blue;">string</span> username)
{
<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> roles = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"SELECT Roles.Rolename FROM Roles INNER JOIN UsersRoles ON Roles.Id = UsersRoles.IdRolename INNER JOIN Users ON UsersRoles.IdUsername = Users.Id WHERE Users.Username = @UserName ORDER BY Roles.Rolename"</span>, connection))
{
cmd.Parameters.Add(<span style="color: #a31515;">"@UserName"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = username;
connection.Open();
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlDataReader</span> reader = cmd.ExecuteReader())
{
<span style="color: blue;">if</span> (reader.HasRows)
{
<span style="color: blue;">while</span> (reader.Read())
{
roles.Add(reader.GetString(0));
}
}
}
}
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerRoleProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ProviderException</span>(ExceptionMessage);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;">return</span> roles.ToArray();
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Get Users In Role</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"roleName"</span><span style="color: grey;">></span><span style="color: green;">name of role</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">list of users</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">string</span>[] GetUsersInRole(<span style="color: blue;">string</span> roleName)
{
<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> users = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
connection.Open();
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlCommand</span> cmd = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlCommand</span>(<span style="color: #a31515;">"SELECT Users.Username FROM Roles INNER JOIN UsersRoles ON Roles.Id = UsersRoles.IdRolename INNER JOIN Users ON UsersRoles.IdUsername = Users.Id WHERE (Roles.Rolename = @RoleName) ORDER BY Users.Username"</span>, connection))
{
cmd.Parameters.Add(<span style="color: #a31515;">"@RoleName"</span>, <span style="color: #2b91af;">SqlDbType</span>.NVarChar).Value = roleName;
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlDataReader</span> reader = cmd.ExecuteReader())
{
<span style="color: blue;">if</span> (reader.HasRows)
{
<span style="color: blue;">while</span> (reader.Read())
{
users.Add(reader.GetString(0));
}
}
}
}
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerRoleProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ProviderException</span>(ExceptionMessage);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: blue;">return</span> users.ToArray();
}</pre>
<br />
Infine il metodo RemoveUsersFromRoles rimuove l'associazione ruolo - utente quando c'è una eliminazione di un ruolo o di un utente e pertanto viene chiamata prima del metodo di eliminazione utente o ruolo. Se abbiamo impostato l'azione di CASCATE in eliminazione questo metodo può anche non essere riscritto.<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Remove Users From Roles</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"usernames"</span><span style="color: grey;">></span><span style="color: green;">list of users</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"roleNames"</span><span style="color: grey;">></span><span style="color: green;">list of roles</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> RemoveUsersFromRoles(<span style="color: blue;">string</span>[] usernames, <span style="color: blue;">string</span>[] roleNames)
{
<span style="color: #2b91af;">SqlTransaction</span> transaction = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
<span style="color: blue;">int</span>[] idUsers = <span style="color: blue;">this</span>.Users(usernames);
<span style="color: blue;">int</span>[] idRoles = <span style="color: blue;">this</span>.Roles(roleNames);
<span style="color: blue;">using</span> (<span style="color: #2b91af;">SqlConnection</span> connection = <span style="color: blue;">new</span> <span style="color: #2b91af;">SqlConnection</span>(<span style="color: blue;">this</span>.connectionString))
{
connection.Open();
transaction = connection.BeginTransaction(<span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
<span style="color: #2b91af;">SqlCommand</span> cmd = connection.CreateCommand();
cmd.Connection = connection;
cmd.Transaction = transaction;
<span style="color: blue;">foreach</span> (<span style="color: blue;">int</span> u <span style="color: blue;">in</span> idUsers)
{
<span style="color: blue;">foreach</span> (<span style="color: blue;">int</span> r <span style="color: blue;">in</span> idRoles)
{
cmd.CommandText = <span style="color: #a31515;">"DELETE FROM UsersRoles"</span> +
<span style="color: #a31515;">" WHERE IdRolename = @IdRole AND IdUsername = @IdUser"</span>;
cmd.Parameters.Clear();
cmd.Parameters.Add(<span style="color: #a31515;">"@IdRole"</span>, <span style="color: #2b91af;">SqlDbType</span>.Int).Value = r;
cmd.Parameters.Add(<span style="color: #a31515;">"@IdUser"</span>, <span style="color: #2b91af;">SqlDbType</span>.Int).Value = u;
cmd.ExecuteNonQuery();
}
}
transaction.Commit();
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerRoleProvider</span>.WriteToEventLog(e, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
<span style="color: blue;">if</span> (transaction != <span style="color: blue;">null</span>)
{
<span style="color: blue;">try</span>
{
transaction.Rollback();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e2)
{
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.WriteExceptionsToEventLog)
{
<span style="color: #2b91af;">ArcGisServerRoleProvider</span>.WriteToEventLog(e2, <span style="color: #2b91af;">MethodBase</span>.GetCurrentMethod().Name);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span>;
}
}
}
}
}</pre>
<br />
Il seguente metodo di supporto scrive le eventuali eccezioni nell'event viewer di Windows:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> WriteToEventLog</span>
<span style="color: grey;">///</span><span style="color: green;"> A helper function that writes exception detail to the event log. Exceptions</span>
<span style="color: grey;">///</span><span style="color: green;"> are written to the event log as a security measure to avoid private database</span>
<span style="color: grey;">///</span><span style="color: green;"> details from being returned to the browser. If a method does not return a status</span>
<span style="color: grey;">///</span><span style="color: green;"> or boolean indicating the action succeeded or failed, a generic exception is also </span>
<span style="color: grey;">///</span><span style="color: green;"> thrown by the caller.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"e"</span><span style="color: grey;">></span><span style="color: green;">object exception</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"action"</span><span style="color: grey;">></span><span style="color: green;">value of action</span><span style="color: grey;"></param></span>
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> WriteToEventLog(<span style="color: #2b91af;">Exception</span> e, <span style="color: blue;">string</span> action)
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">EventLog</span> log = <span style="color: blue;">new</span> <span style="color: #2b91af;">EventLog</span>();
log.Source = <span style="color: #2b91af;">ArcGisServerMembershipProvider</span>.EventSource;
log.Log = <span style="color: #2b91af;">ArcGisServerMembershipProvider</span>.EventLog;
<span style="color: blue;">string</span> message = <span style="color: #a31515;">"An exception occurred communicating with the data source.\n\n"</span>;
message += <span style="color: #a31515;">"Action: "</span> + action + <span style="color: #a31515;">"\n\n"</span>;
message += <span style="color: #a31515;">"Exception: "</span> + e.ToString();
log.WriteEntry(message);
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
}</pre>
<br />
<br />
Se si opta per l'event viewer occorre registrare l'event source. E' possibile anche tramite riga di comando aprendo la console di Powershell e digitando:<br />
<br />
New-EventLog -LogName Application -Source AGSMembershipProvider<br />
New-EventLog -LogName Application -Source AGSRoleProvider <br />
<br />
mentre per deregistrali:<br />
<br />
Remove-EventLog -Source AGSMembershipProvider<br />
Remove-EventLog -Source AGSRoleProvider <br />
<br />
In questo esempio abbiamo utilizzato l'event log Application. In questo caso con il filtro sulla source possiamo crearci una Custom View per facilitarci la lettura.<br />
<pre><code> </code></pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXq7EXtbYMy-4m-mkNGOm0iOmNRucbh8cNHPVnLFeL9lDNA8sfBrqC5t8TiRssX6GqWyXGKmarvJW48iWE06ELKlBzkOQwQu32qVV1iv92lXFuvBlaylUx7bAu4XZermz4rcDfDngF6jdV/s1600/CustomProvider3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXq7EXtbYMy-4m-mkNGOm0iOmNRucbh8cNHPVnLFeL9lDNA8sfBrqC5t8TiRssX6GqWyXGKmarvJW48iWE06ELKlBzkOQwQu32qVV1iv92lXFuvBlaylUx7bAu4XZermz4rcDfDngF6jdV/s1600/CustomProvider3.png" height="242" width="640" /></a></div>
<pre></pre>
<br />
La dll, una volta firmata e compilata, la registriamo nella GAC tramite il comando:<br />
<br />
<div style="text-align: center;">
gacutil /i ArcGisServerCustomProvider.dll</div>
<br />
o se non abbiamo sul server l'utility gacutil (ad esempio non è installato l'sdk .NET) possiamo tramite drag and drop trascinarla nella cartella di assembly.<br />
<br />
Per disinstallarla:<br />
<div style="text-align: center;">
gacutil /u ArcGisServerCustomProvider</div>
<br />
oppure dalla cartella di assembly selezionare l'assembly e tramite il menu che compare cliccando il tasto destro del mouse cliccare su disinstalla.<br />
<br />
A questo punto registriamo il nostro custom identity store in ArcGIS Server Administrator.<br />
<br />
La configurazione dovrà essere in formato json.<br />
Le proprietà sono:<br />
<b>type</b>: indicare 'ASP_NET'<br />
<b>class</b>: indicare i riferimenti dell'assembly e della classe che implementa il Membership e il Role<br />
<b>properties</b>: lista delle proprietà che verranno passate all'initialize<br />
<br />
Pertanto per lo user store configuration sarà:<br />
<br />
{<br />
"type": "ASP_NET",<br />
"class": "ArcGisServerCustomProvider.ArcGisServerMembershipProvider,ArcGisServerCustomProvider,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=e70ef8c9eb62a069",<br />
"properties": {<br />
"connectionStringName": "Data Source=.\\SQLEXPRESS;Initial Catalog=YourDB;User Id=YourUser;Password=YourPwd;",<br />
"writeExceptionsToEventLog": "true"<br />
}<br />
}<br />
<br />
mentre per il role store configuration sarà:<br />
{<br />
"type": "ASP_NET",<br />
"class": "ArcGisServerCustomProvider.ArcGisServerRoleProvider,ArcGisServerCustomProvider,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=e70ef8c9eb62a069",<br />
"properties": {<br />
"connectionStringName": "Data Source=.\\SQLEXPRESS;Initial Catalog=YourDB;User Id=YourUser;Password=YourPwd;",<br />
"writeExceptionsToEventLog": "true"<br />
}<br />
}<br />
<br />
Consiglio: prima di aggiornare la configurazione testare il controllo formale dei propri json tramite strumenti tipo <a href="http://jsonlint.com/" target="_blank">jsonlint</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKZrSD4Z_rfnD262qc8SppgG4Gf3eAEeJpal5SEWEi3YJ9eRyCAN6Zia04gx6O-JFyx8MMzHqA40fDNXhapenZ7wCwTkVM7GiLzc4zCxK2_2O8i8l8GuxGUvTROmK94tlQ4kpquDZaKa59/s1600/CustomProvider4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKZrSD4Z_rfnD262qc8SppgG4Gf3eAEeJpal5SEWEi3YJ9eRyCAN6Zia04gx6O-JFyx8MMzHqA40fDNXhapenZ7wCwTkVM7GiLzc4zCxK2_2O8i8l8GuxGUvTROmK94tlQ4kpquDZaKa59/s1600/CustomProvider4.png" height="520" width="640" /></a></div>
<br />
<br />
<br />
<a href="http://www.studioat.eu/downloads/arcgisservercustomprovider.zip" target="_blank">Qui</a> è possibile scaricare la soluzione completa.<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com8Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-77239580710023277582014-01-31T22:39:00.000+01:002014-03-12T15:55:24.598+01:00SQL injectionSQL injection è una tecnica molto diffusa dell'<a href="http://it.wikipedia.org/wiki/Hacking" target="_blank">hacking</a> che attacca applicazioni web che si appoggiano a DBMS di tipo SQL. In pratica questo <a href="http://it.wikipedia.org/wiki/Exploit" target="_blank">exploit</a> sfrutta l'inefficienza dei controlli sui dati di input inserendo codice maligno all'interno di query SQL per, ad esempio, autenticarsi in un sito, modificare dati o leggere informazioni del db.<br />
Vediamo un semplicissimo esempio ma giusto per far capire il problema perchè le tecniche dell'hacking SQL injection ma anche <a href="https://www.owasp.org/index.php/Blind_SQL_Injection" target="_blank">Blind SQL injection</a> possono essere molto più sofisticate utilizzando funzioni del database sottostante.<br />
Supponiamo di avere una pagina web di login con user e password per l'autenticazione ad un sito:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeXTp0OpjJZthl2iO1HjqqHqQWPZXXvrU_qtU01f8kppvgakKKoFVWR2a8bytitQkC2XT9lkZ59vjM-AnaYd51wAz-CG9CPYegJalBWFwjgmZyPwrvxbP5mithMC4_9HaZNniJ9wa3xgff/s1600/sqlinjection1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeXTp0OpjJZthl2iO1HjqqHqQWPZXXvrU_qtU01f8kppvgakKKoFVWR2a8bytitQkC2XT9lkZ59vjM-AnaYd51wAz-CG9CPYegJalBWFwjgmZyPwrvxbP5mithMC4_9HaZNniJ9wa3xgff/s1600/sqlinjection1.png" height="89" width="640" /></a></div>
Nel pulsante di login lo sviluppatore ha scritto codice del tipo:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">string</span> sqlLogin = <span style="color: #a31515;">"Select Id from tblUsers where User='"</span> + TxtUser.Text + <span style="color: #a31515;">"' and pwd='"</span> + txtPwd.Text + <span style="color: #a31515;">"'"</span>;
</pre>
<br />
Ora se sulla pagina web scriviamo, per accedere come utente Pippo, qualcosa del tipo:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_MwFtuu_XNj-ItJ89pqne1qEib3rR5stQ1eFSJHIEs-zygbGFThkUDRDE8H1UV9AjoelF7uBy1vcYVrlQIvKw794cuWccoZFniB9Etv9vT-ehv9qCT2Q1flFw3adHCEEr_FZcLQ_QKN2Y/s1600/sqlinjection3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_MwFtuu_XNj-ItJ89pqne1qEib3rR5stQ1eFSJHIEs-zygbGFThkUDRDE8H1UV9AjoelF7uBy1vcYVrlQIvKw794cuWccoZFniB9Etv9vT-ehv9qCT2Q1flFw3adHCEEr_FZcLQ_QKN2Y/s1600/sqlinjection3.png" height="90" width="640" /></a></div>
La stringa che verrà eseguita nel database sarà:<br />
<br />
<div style="text-align: center;">
Select Id from tblUsers where User='Qualsiasi cosa' and pwd='' Or User = 'Pippo'</div>
<br />
che sarà vera per l'utente Pippo avendo aggiunto come operatore logico una <a href="http://it.wikipedia.org/wiki/Disgiunzione_inclusiva" target="_blank">disgiunzione inclusiva</a>.<br />
<br />
ArcGIS Server, via SOAP o REST permette ovviamente di interrogare i dati e quindi potrebbe non essere immune a questo tipo di vulnerabilità. <br />
Dalla versione 10.2 abbiamo a disposizione in <span class="hps">ArcGIS</span> <span class="hps">Server </span><span class="hps">un'opzione di sicurezza</span> <span class="hps">che obbliga</span> <span class="hps">gli sviluppatori ad utilizzare</span> <span class="hps">interrogazioni SQL</span> <span class="hps">standard</span> <span class="hps">quando si lavora</span> <span class="hps">con i servizi di</span> <span class="hps">mappa</span>, <span class="hps">feature</span>, <span class="hps">image </span><span class="hps">e</span> <span class="hps">WFS</span> <span class="hps">attraverso</span> <span class="hps">REST</span> <span class="hps">o</span> <span class="hps">SOAP</span>. <span class="hps">Questo aiuta a prevenire</span> <span class="hps">gli attacchi </span><span class="hps">SQL injection</span> <span class="hps">ed</span> <span class="hps">inoltre</span> <span class="hps">rende più facile</span> <span class="hps">la vita per gli sviluppatori e</span> <span class="hps">le applicazioni</span> che<span class="hps"> interrogano</span> <span class="hps">i servizi</span> <span class="hps">ArcGIS</span> <span class="hps">Server.</span> <span class="hps">Le query</span> <span class="hps">standardizzate</span> <span class="hps">vengono applicate</span> <span class="hps">per impostazione predefinita,</span> <span class="hps">ma</span> <span class="hps">possono essere disattivate</span><span class="hps"> dall'amministratore del server</span>.<br />
Per disabilitare questa opzione di sicurezza e <span style="color: red;"><u><i>quindi rendere più vulnerabile il sistema agli attacchi SQL injection</i></u></span> è possibile loggarsi all'Administrator directory (<span id="GUID-69488B1F-3A07-45EF-BAAA-54F4E0C0B060"><span class="usertext">http://myserver:6080/arcgis/admin</span>) e impostare nella finestra di dialogo in system -> properties -> update :</span><br />
<br />
<div style="text-align: center;">
<pre><code>{"standardizedQueries": "false"}</code></pre>
<pre><code> </code></pre>
<div style="text-align: justify;">
<pre><code></code></pre>
</div>
</div>
<br />
Cliccare su <b>update </b>e riavviare ArcGIS Server.<br />
<br />
Se, quando si visualizza la finestra di dialogo non è presente nessuna proprietà o {"standardizedQueries": "true"}, allora significa che le query standardizzate sono attive. Occorre ricordare che le query standardizzate sono applicate a tutto il site e pertanto non è possibile abilitarle solo per alcuni servizi e non per altri. Lo sviluppatore ha la possibilità di verificare se uno specifico layer o tabella del servizio è impostato per le query standardizzate direttamente all'end point : <span class="usertext"> </span><br />
<br />
<div style="text-align: center;">
<span class="usertext">http://myserver:6080/myinstance/rest/services/folder/service/service type/0.</span></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFUBmJKV2QhALb7FhQTI7n_Kx15FEu0GHW5pDi16aCIgcxSLHKWbWUoj92IakcOvAwm_LzrNOQcwReD6maM_EqBVTjV5Xp9M94OdrkINI0OP0h83cKYCZXaI-b90On4QFwpDSfXePGnDMM/s1600/sqlinjection2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFUBmJKV2QhALb7FhQTI7n_Kx15FEu0GHW5pDi16aCIgcxSLHKWbWUoj92IakcOvAwm_LzrNOQcwReD6maM_EqBVTjV5Xp9M94OdrkINI0OP0h83cKYCZXaI-b90On4QFwpDSfXePGnDMM/s1600/sqlinjection2.png" height="640" width="416" /></a></div>
<br />
<br />
In questo <a href="http://resources.arcgis.com/en/help/main/10.2/0154/015400000686000000.htm" target="_blank">link</a> potete verificare quali sono le funzioni SQL che è possibile utilizzare per generare query standardizzate che possono essere utilizzate nelle applicazioni per interrogare servizi di mappa, feature, image e WFS.<br />
Quando le query standardizzate sono abilitate ArcGIS Server verifica la sintassi standard e non consente le funzioni e le sintassi specifiche del database. Pertanto se lo sviluppatore utilizza funzioni specifiche del database o rivede le proprie query o dovrà disabilitare le query standardizzate a livello di site.<br />
Le query standardizzate hanno delle limitazioni: non sono supportate su join tra workspace differenti; inoltre tabelle di database a <span class="hps">cui si accede</span> <span class="hps">attraverso un</span> <span class="hps">file di connessione</span> OLE connection non sono supportate. <span class="hps">Se i dati</span> <span class="hps">del servizio contengono</span> <span class="hps">queste sorgenti</span>, <span class="hps">è necessario</span> <span class="hps">utilizzare</span> <span class="hps">metodi alternativi</span> <span class="hps">per fare riferimento</span> a<span class="hps">i vostri</span> <span class="hps">dati</span>. Anche le Subqueries nella clausola <i>WHERE</i> non sono supportate.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-50665974396407048202013-12-31T19:44:00.000+01:002014-01-14T17:49:18.257+01:00QR Code MapCon lo sviluppo del mercato degli smartphone il <a href="http://it.wikipedia.org/wiki/Codice_QR" target="_blank">QR</a> (Quick Response) Code ha acquisito notorietà visto la facilità di poterli decodificare utilizzando la fotocamera del device. <br />
Uno tra le principali library che permette di generare e decodificare anche il QR Code è <a href="https://zxingnet.codeplex.com/" target="_blank">ZXing.NET</a>.<br />
Poichè nel crittogramma possiamo codificare informazioni, possiamo inventarci innumerevoli funzionalità da trasmettere agli smartphone: da semplici url con parametri nel querystring ad informazioni gestite opportunamente dalle app installate sugli smartphone.<br />
In questo <a href="http://blogs.esri.com/esri/apl/2013/09/27/qr-map-for-windows-store/" target="_blank">esempio </a>la mappa sul tablet è sincronizzata agli spostamenti della mappa a monitor perchè il QR Code è generato dinamicamente ad ogni cambio extent e nel QR Code è memorizzato il corrente extent della mappa; la fotocamera decodifica il QR Code ed applica il nuovo extent alla mappa sul tablet. In questo caso è stata applicata una <a href="http://kiwigis.blogspot.it/2013/09/base-93-integer-shortening-in-c.html" target="_blank">compressione</a> all'informazione per semplificare il crittogramma e rendere ancora più veloce la decodifica.<br />
Ma vediamo una semplice <a href="http://it.wikipedia.org/wiki/Proof_of_concept" target="_blank">Proof of concept</a> che codifica un indirizzo di mappa. In questo caso potremmo utilizzare l'indirizzo del Map Viewer arcgis.com che accetta <a href="http://resources.arcgis.com/it/help/arcgisonline/index.html#//010q00000098000000" target="_blank">parametri via url</a>. Nel caso specifico passeremo l'extent (parametro extent) e la web map da visualizzare (parametro webmap) e restituiremo un url abbreviato appoggiandoci ad un servizio di <a href="http://it.wikipedia.org/wiki/Abbreviazione_degli_URL" target="_blank">URL shortening</a> (Goo.gl, bit.ly ecc.) o creandoci il nostro utilizzando ad esempio <a href="http://archive.msdn.microsoft.com/rewriteextensibility" target="_blank">URL Rewrite Module</a> di IIS così da avere un crittogramma semplificato.<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> handle qr Code</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"boundVariables"</span><span style="color: grey;">></span><span style="color: green;">bound Variables</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationInput"</span><span style="color: grey;">></span><span style="color: green;">object operationInput</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">object outputFormat</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">object requestProperties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">object responseProperties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">return handle rest request</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">byte</span>[] QrCodeOperatorHandler(<span style="color: #2b91af;">NameValueCollection</span> boundVariables, <span style="color: #2b91af;">JsonObject</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"application/json\"}"</span>;
<span style="color: blue;">string</span> textValue;
<span style="color: blue;">bool</span> found = operationInput.TryGetString(<span style="color: #a31515;">"text"</span>, <span style="color: blue;">out</span> textValue);
<span style="color: blue;">if</span> (!found || <span style="color: blue;">string</span>.IsNullOrEmpty(textValue))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"text"</span>);
}
<span style="color: blue;">bool</span> useShortenerUrl = <span style="color: blue;">true</span>;
<span style="color: blue;">bool</span>? useShortenerUrlValue;
found = operationInput.TryGetAsBoolean(<span style="color: #a31515;">"useShortenerUrl"</span>, <span style="color: blue;">out</span> useShortenerUrlValue);
<span style="color: blue;">if</span> (found && useShortenerUrlValue.HasValue)
{
useShortenerUrl = useShortenerUrlValue.Value;
}
<span style="color: blue;">try</span>
{
<span style="color: blue;">if</span> ((outputFormat == <span style="color: #a31515;">"json"</span>) || (outputFormat == <span style="color: #a31515;">"image"</span>))
{
<span style="color: blue;">if</span> (useShortenerUrl)
{
<span style="color: blue;">if</span> (!<span style="color: #2b91af;">ShortenerUrl</span>.CheckUrl(textValue))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">QRCoderException</span>(<span style="color: #a31515;">"url wrong!"</span>);
}
ShortUrl shortUrl = <span style="color: blue;">new</span> ShortUrl();
shortUrl.OriginalUrl = textValue;
shortUrl.CodeShortUrl = <span style="color: #2b91af;">ShortenerUrl</span>.UniqueShortUrl(shortUrl.PrefixShortUrl);
shortUrl.Expire = <span style="color: blue;">true</span>;
shortUrl.ShortenedUrl = <span style="color: blue;">null</span>;
<span style="color: #2b91af;">ShortenerUrl</span>.AddUrlToDatabase(<span style="color: blue;">ref</span> shortUrl);
textValue = <span style="color: #2b91af;">ShortenerUrl</span>.PublicShortUrl(<span style="color: blue;">this</span>.shortenerUrl, shortUrl.ShortenedUrl);
}
<span style="color: #2b91af;">QRCodeGenerator</span> qrGenerator = <span style="color: blue;">new</span> <span style="color: #2b91af;">QRCodeGenerator</span>();
<span style="color: #2b91af;">QRCodeGenerator</span>.<span style="color: #2b91af;">QRCode</span> qrCode = qrGenerator.CreateQrCode(textValue, <span style="color: #2b91af;">QRCodeGenerator</span>.<span style="color: #2b91af;">ECCLevel</span>.Q);
<span style="color: blue;">using</span> (System.Drawing.<span style="color: #2b91af;">Bitmap</span> image = qrCode.GetGraphic(20))
{
<span style="color: blue;">if</span> (outputFormat == <span style="color: #a31515;">"json"</span>)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"application/json\"}"</span>;
<span style="color: blue;">string</span> fileName = System.IO.<span style="color: #2b91af;">Path</span>.ChangeExtension(<span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"_ags_{0}"</span>, Guid.NewGuid().ToString()), <span style="color: #a31515;">"png"</span>);
<span style="color: blue;">string</span> pathfileName = System.IO.<span style="color: #2b91af;">Path</span>.Combine(<span style="color: blue;">this</span>.pathOutputAGS, fileName);
image.Save(pathfileName, System.Drawing.Imaging.<span style="color: #2b91af;">ImageFormat</span>.Png);
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
jsonObject.AddString(<span style="color: #a31515;">"url"</span>, <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"{0}/{1}"</span>, <span style="color: blue;">this</span>.pathOutputVirtualAGS, fileName));
jsonObject.AddLong(<span style="color: #a31515;">"status_code"</span>, 200);
jsonObject.AddString(<span style="color: #a31515;">"status_txt"</span>, <span style="color: #a31515;">"OK"</span>);
jsonObject.AddString(<span style="color: #a31515;">"text"</span>, textValue);
<span style="color: blue;">return</span> <span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(jsonObject.ToJson());
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (outputFormat == <span style="color: #a31515;">"image"</span>)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"image/png\"}"</span>;
<span style="color: blue;">return</span> <span style="color: #2b91af;">Helper</span>.ImageToByte(image, System.Drawing.Imaging.<span style="color: #2b91af;">ImageFormat</span>.Png);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">QRCoderException</span>(<span style="color: #a31515;">"Format output not found!"</span>);
}
}
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">QRCoderException</span>(<span style="color: #a31515;">"Format output not found!"</span>);
}
}
<span style="color: blue;">catch</span>
{
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
jsonObject.AddLong(<span style="color: #a31515;">"status_code"</span>, 503);
jsonObject.AddString(<span style="color: #a31515;">"status_txt"</span>, <span style="color: #a31515;">"UNKNOWN_ERROR"</span>);
<span style="color: blue;">return</span> <span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(jsonObject.ToJson());
}
}</pre>
Qui possiamo vedere la soe <a href="http://sit2.sistemigis.it/sit/rest/services/Demo/WPS/MapServer/exts/UtilityWPSSOE/qrCode" target="_blank">online</a>.<br />
<br />
Richiamiamo la soe per generare qr code dinamici da un template js arcgis:<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> require([<span style="color: #a31515;">"esri/lang"</span>, <span style="color: #a31515;">"esri/request"</span>], lang.hitch(<span style="color: blue;">this</span>, <span style="color: blue;">function</span> (esriLang, esriRequest) {
<span style="color: blue;">this</span>.map.on(<span style="color: #a31515;">"extent-change"</span>, lang.hitch(<span style="color: blue;">this</span>, <span style="color: blue;">function</span> () {
extent = <span style="color: blue;">this</span>.map.geographicExtent;
<span style="color: blue;">var</span> params = { f: <span style="color: #a31515;">"json"</span>,
text: esriLang.substitute({host: <span style="color: blue;">this</span>.config.sharinghost, webmap: <span style="color: blue;">this</span>.config.webmap, xmin: extent.xmin, ymin: extent.ymin, xmax: extent.xmax, ymax: extent.ymax }, <span style="color: #a31515;">"${host}/home/webmap/viewer.html?webmap=${webmap}&extent=${xmin},${ymin},${xmax},${ymax}"</span>),
useShortenerUrl: <span style="color: blue;">true</span>
};
<span style="color: blue;">var</span> requestHandle = esriRequest({
url: <span style="color: blue;">this</span>.config.qrcodeSOE,
content: params,
callbackParamName: <span style="color: #a31515;">"callback"</span>
}, { useProxy: <span style="color: blue;">false</span> });
requestHandle.then(
<span style="color: blue;">function</span> (response) {
<span style="color: blue;">var</span> qrcodeImg = dom.byId(<span style="color: #a31515;">"qrcodeImg"</span>);
<span style="color: blue;">var</span> qrcodeAnchor = dom.byId(<span style="color: #a31515;">"qrcodeAnchor"</span>);
<span style="color: blue;">if</span> (response.status_code === 200) {
qrcodeImg.src = response.url;
qrcodeAnchor.href = response.text;
}
<span style="color: blue;">else</span> {
console.log(<span style="color: #a31515;">"Error: "</span>, response.status_txt);
}
}, <span style="color: blue;">function</span> (error) {
console.log(<span style="color: #a31515;">"Error: "</span>, error.message);
});
}));
}));
</pre>
<br />
<br />
Qui vediamo l'esempio <a href="http://www.appgis.it/qrcodemap" target="_blank">online</a>.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-59542745612180311872013-11-30T20:42:00.000+01:002014-01-11T17:56:42.567+01:00Servizio WCTS del PCNSin dalla versione 10.1, ArcGIS Server permette di esporre un servizio arcgis server di geoprocessing come <a href="http://www.opengeospatial.org/standards/wps" target="_blank">WPS</a> (<a href="https://www.blogger.com/null" name="what">Web Processing Service) </a>ovvero uno standard OGC per esporre modelli di geoprocessing come servizio web mediante un'interfaccia standardizzata <span _mstdst="0_44:46" _mstsrc="0_37:40" class="dhighlight" id="Dst[0][37:40:44:46]">che</span> <span _mstdst="0_48:55" _mstsrc="0_42:52" id="Dst[0][42:52:48:55]">facilita</span> <span _mstdst="0_57:58" _mstsrc="0_54:56" id="Dst[0][54:56:57:58]">la</span> <span _mstdst="0_60:72" _mstsrc="0_58:67" id="Dst[0][58:67:60:72]">pubblicazione</span> <span _mstdst="0_97:97" _mstsrc="0_94:96" id="Dst[0][94:96:97:97]">e</span> <span _mstdst="0_99:100" _mstsrc="0_98:100" id="Dst[0][98:100:99:100]">l'utilizzo </span><span _mstdst="0_129:130" _mstsrc="0_127:128" id="Dst[0][127:128:129:130]">dei '</span><span _mstdst="0_132:135" _mstsrc="0_130:134" id="Dst[0][130:134:132:135]"></span><span _mstdst="0_137:144" _mstsrc="0_136:144" id="Dst[0][136:144:137:144]">processi'</span> <span _mstdst="0_146:148" _mstsrc="0_146:147" id="Dst[0][146:147:146:148]">da parte dei</span> <span _mstdst="0_150:155" _mstsrc="0_149:155" id="Dst[0][149:155:150:155]">client</span>.<br />
Ad oggi ArcGIS non dispone di un client per poter 'consumare' i servizi WPS ma, essendo servizi che utilizzano standard di comunicazione, possiamo effettuare direttamente le chiamate in HTTP GET o in HTTP POST o mediante messaggi SOAP.<br />
Come esempio di prova possiamo prendere in considerazione il servizio WCTS del PCN (Portale Cartografico Nazionale) cioè il servizio web di trasformazione delle coordinate realizzato come Application Profile di WPS. Il servizio utilizza i grigliati IGM e copre tutto il territorio nazionale.<br />
<br />
Le operazioni messe a disposizione del WPS sono: getCapabilities, DescribeProcess ed Execute.<br />
<br />
<div name="div[0]">
<span _mstdst="0_0:11" _mstsrc="0_20:28" id="Dst[0][20:28:0:11]">L'operazione</span> di <span _mstdst="0_16:30" _mstsrc="0_4:18" id="Dst[0][4:18:16:30]">getCapabilities</span> <span _mstdst="0_32:39" _mstsrc="0_30:37" id="Dst[0][30:37:32:39]">fornisce</span> <span _mstdst="0_41:49" _mstsrc="0_39:44" id="Dst[0][39:44:41:49]">l'accesso</span> <span _mstdst="0_51:51" _mstsrc="0_46:47" id="Dst[0][46:47:51:51]">ad</span> <span _mstdst="0_53:64" _mstsrc="0_57:67" id="Dst[0][57:67:53:64]">informazioni</span> <span _mstdst="0_66:73" _mstsrc="0_49:55" id="Dst[0][49:55:66:73]">generali</span> <span _mstdst="0_75:76" _mstsrc="0_69:73" id="Dst[0][69:73:75:76]">su</span> <span _mstdst="0_78:95" _mstsrc="0_86:99" class="dhighlight" id="Dst[0][86:99:78:95]">un'implementazione</span> <span _mstdst="0_97:103" _mstsrc="0_77:80" id="Dst[0][77:80:97:103]">diretta</span> del <span _mstdst="0_108:110" _mstsrc="0_82:84" id="Dst[0][82:84:108:110]">WPS</span> <span _mstdst="0_112:113" _mstsrc="0_102:104" id="Dst[0][102:104:112:113]">ed</span> <span _mstdst="0_115:120" _mstsrc="0_106:110" id="Dst[0][106:110:115:120]">elenca</span> <span _mstdst="0_122:123" _mstsrc="0_112:114" id="Dst[0][112:114:122:123]">le</span> <span _mstdst="0_125:134" _mstsrc="0_116:125" id="Dst[0][116:125:125:134]">operazioni</span> <span _mstdst="0_136:136" _mstsrc="0_127:129" id="Dst[0][127:129:136:136]">e</span> i <span _mstdst="0_140:145" _mstsrc="0_138:144" id="Dst[0][138:144:140:145]">metodi</span> di <span _mstdst="0_150:156" _mstsrc="0_131:136" id="Dst[0][131:136:150:156]">accesso</span> <span _mstdst="0_158:167" _mstsrc="0_146:154" id="Dst[0][146:154:158:167]">supportati</span> <span _mstdst="0_169:170" _mstsrc="0_156:157" id="Dst[0][156:157:169:170]">da</span> <span _mstdst="0_172:175" _mstsrc="0_159:162" id="Dst[0][159:162:172:175]">tale</span> <span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">implementazione. L'implementazione deve supportare l'operazione di getCapabilities via HTTP GET mentre il supporto HTTP POST è opzionale.</span></div>
<div name="div[0]">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><br /></span></div>
<div name="div[0]">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">Via HTTP GET possiamo fornire i parametri di richiesta come KVP (Key Value Pair) codificate. Nel nostro esempio (ho inserito solo le KVP obbligatorie):</span></div>
<div name="div[0]">
</div>
<div name="div[0]" style="text-align: center;">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"></span><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">http://wms.pcn.minambiente.it/wps?service=wps&request=getCapabilities</span></div>
<div name="div[0]">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><br /></span></div>
<div name="div[0]">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">O via POST:</span></div>
<div name="div[0]">
</div>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13;"><span style="color: #2b91af;"> XElement</span> root = <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(
<span style="color: #2b91af;">Global</span>.wps + <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">RequestWPS</span>), <span style="color: #2b91af;">RequestWPS</span>.getCapabilities),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"ows"</span>, <span style="color: #2b91af;">Global</span>.ows.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"wps"</span>, <span style="color: #2b91af;">Global</span>.wps.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"xlink"</span>, <span style="color: #2b91af;">Global</span>.xlink.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"xsi"</span>, <span style="color: #2b91af;">Global</span>.xsi.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">Global</span>.xsi + <span style="color: #a31515;">"schemaLocation"</span>, <span style="color: #2b91af;">Global</span>.schemaLocation.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"language"</span>, <span style="color: #a31515;">"en"</span>),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"service"</span>, <span style="color: #2b91af;">Global</span>.serviceWPS),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"AcceptVersions"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Version"</span>, <span style="color: #2b91af;">Global</span>.versionWPS)));
<span style="color: #2b91af;">XDocument</span> xDoc = <span style="color: blue;">new</span> <span style="color: #2b91af;">XDocument</span>(<span style="color: blue;">new</span> <span style="color: #2b91af;">XDeclaration</span>(<span style="color: #2b91af;">Global</span>.versionXML, <span style="color: #2b91af;">Encoding</span>.UTF8.WebName, <span style="color: blue;">null</span>), root);
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> mem = <span style="color: blue;">new</span> <span style="color: #2b91af;">MemoryStream</span>())
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> writer = <span style="color: blue;">new</span> <span style="color: #2b91af;">XmlTextWriter</span>(mem, <span style="color: #2b91af;">Encoding</span>.UTF8))
{
writer.Formatting = <span style="color: #2b91af;">Formatting</span>.Indented;
xDoc.WriteTo(writer);
writer.Flush();
mem.Flush();
mem.Seek(0, <span style="color: #2b91af;">SeekOrigin</span>.Begin);
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> reader = <span style="color: blue;">new</span> <span style="color: #2b91af;">StreamReader</span>(mem))
{
<span style="color: blue;">string</span> xml = reader.ReadToEnd();
<span style="color: #2b91af;">XDocument</span> xDocument = <span style="color: blue;">this</span>.ResponseWCTSPCN(xml);
<span style="color: blue;">var</span> result = xDocument.Elements().Where(k => (k.Name == <span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Capabilities"</span>)).Elements().Where(h => (h.Name == <span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"ProcessOfferings"</span>)).Elements().Where(x => (x.Name == <span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Process"</span>));
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> e <span style="color: blue;">in</span> result)
{
<span style="color: blue;">if</span> (e.Elements().Where(x => (x.Name == <span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Identifier"</span>) && (x.Value == <span style="color: blue;">this</span>.wctsPCNIdentifier)).Count() == 1)
{
jsonObject.AddString(<span style="color: #a31515;">"title"</span>, e.Elements().Where(x => (x.Name == <span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Title"</span>)).Select(x => x.Value).FirstOrDefault());
jsonObject.AddString(<span style="color: #a31515;">"abstract"</span>, e.Elements().Where(x => (x.Name == <span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Abstract"</span>)).Select(x => x.Value).FirstOrDefault());
<span style="color: blue;">break</span>;
}
}
}
}</pre>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> return response wps pcn</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"request"</span><span style="color: grey;">></span><span style="color: green;">request wps</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">object XDocument</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">XDocument</span> ResponseWCTSPCN(<span style="color: blue;">string</span> request)
{
<span style="color: #2b91af;">HttpWebRequest</span> webRequest = (<span style="color: #2b91af;">HttpWebRequest</span>)<span style="color: #2b91af;">WebRequest</span>.Create(<span style="color: blue;">this</span>.wctsPCNUrl);
webRequest.Method = <span style="color: #2b91af;">WebRequestMethods</span>.<span style="color: #2b91af;">Http</span>.Post;
<span style="color: blue;">byte</span>[] requestBytes = System.Text.<span style="color: #2b91af;">Encoding</span>.ASCII.GetBytes(request);
webRequest.ContentLength = requestBytes.Length;
webRequest.ContentType = <span style="color: #a31515;">"text/xml;charset=utf-8"</span>;
<span style="color: blue;">using</span> (<span style="color: #2b91af;">Stream</span> streamWriter = webRequest.GetRequestStream())
{
streamWriter.Write(requestBytes, 0, requestBytes.Length);
<span style="color: #2b91af;">HttpWebResponse</span> response = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
response = (<span style="color: #2b91af;">HttpWebResponse</span>)webRequest.GetResponse();
<span style="color: #2b91af;">Console</span>.WriteLine(response.StatusDescription);
<span style="color: blue;">using</span> (<span style="color: #2b91af;">StreamReader</span> streamReader = <span style="color: blue;">new</span> <span style="color: #2b91af;">StreamReader</span>(response.GetResponseStream()))
{
<span style="color: #2b91af;">TextReader</span> textReader = <span style="color: blue;">new</span> <span style="color: #2b91af;">StringReader</span>(streamReader.ReadToEnd());
<span style="color: blue;">return</span> <span style="color: #2b91af;">XDocument</span>.Load(textReader);
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
<span style="color: blue;">finally</span>
{
<span style="color: blue;">if</span> (response != <span style="color: blue;">null</span>)
{
response.Close();
}
}
}
}</pre>
<br />
Qui potete vederla <a href="http://sit2.sistemigis.it/sit/rest/services/Demo/WPS/MapServer/exts/UtilityWPSSOE/wctsPCN?request=getCapabilities&geometries=&export=&sourceCRS=&targetCRS=&f=html" target="_blank">live</a><br />
<br />
<span _mstdst="0_0:11" _mstsrc="0_20:28" class="dhighlight" id="Dst[0][20:28:0:11]">L'operazione</span> <span _mstdst="0_16:30" _mstsrc="0_4:18" id="Dst[0][4:18:16:30]">DescribeProcess</span> <span _mstdst="0_32:39" _mstsrc="0_30:35" id="Dst[0][30:35:32:39]">consente</span> al <span _mstdst="0_44:49" _mstsrc="0_41:47" id="Dst[0][41:47:44:49]">client</span> <span _mstdst="0_51:53" _mstsrc="0_37:39" id="Dst[0][37:39:51:53]">WPS</span> di <span _mstdst="0_59:68" _mstsrc="0_52:58" id="Dst[0][52:58:59:68]">richiedere</span> <span _mstdst="0_70:72" _mstsrc="0_60:60" id="Dst[0][60:60:70:72]">una</span> <span _mstdst="0_74:84" _mstsrc="0_67:77" id="Dst[0][67:77:74:84]">descrizione</span> <span _mstdst="0_86:93" _mstsrc="0_62:65" id="Dst[0][62:65:86:93]">completa</span> <span _mstdst="0_95:96" _mstsrc="0_79:80" id="Dst[0][79:80:95:96]">di</span> <span _mstdst="0_98:100" _mstsrc="0_82:84" id="Dst[0][82:84:98:100]">uno</span> <span _mstdst="0_102:102" _mstsrc="0_86:87" id="Dst[0][86:87:102:102]">o</span> <span _mstdst="0_104:106" _mstsrc="0_89:92" id="Dst[0][89:92:104:106]">più</span> <span _mstdst="0_108:115" _mstsrc="0_94:102" id="Dst[0][94:102:108:115]">processi</span> <span _mstdst="0_117:119" _mstsrc="0_104:107" id="Dst[0][104:107:117:119]">che</span> <span _mstdst="0_121:127" _mstsrc="0_109:111" id="Dst[0][109:111:121:127]">possono</span> <span _mstdst="0_129:134" _mstsrc="0_113:114" id="Dst[0][113:114:129:134]">essere</span> <span _mstdst="0_136:143" _mstsrc="0_116:123" id="Dst[0][116:123:136:143]">eseguiti</span> <span _mstdst="0_145:147" _mstsrc="0_125:126" id="Dst[0][125:126:145:147]">dal</span> <span _mstdst="0_149:156" _mstsrc="0_132:138" id="Dst[0][132:138:149:156]">servizio</span>. <span _mstdst="0_159:164" _mstsrc="0_141:144" id="Dst[0][141:144:159:164]">Questa</span> <span _mstdst="0_166:176" _mstsrc="0_146:156" id="Dst[0][146:156:166:176]">descrizione</span> <span _mstdst="0_178:184" _mstsrc="0_158:165" id="Dst[0][158:165:178:184]">include</span> <span _mstdst="0_186:192" _mstsrc="0_171:175" id="Dst[0][171:175:186:192]">l'input</span> <span _mstdst="0_194:194" _mstsrc="0_177:179" id="Dst[0][177:179:194:194]">e</span> <span _mstdst="0_196:206" _mstsrc="0_188:197" id="Dst[0][188:197:196:206]">i parametri</span> di <span _mstdst="0_211:216" _mstsrc="0_181:186" id="Dst[0][181:186:211:216]">output</span> <span _mstdst="0_218:218" _mstsrc="0_199:201" id="Dst[0][199:201:218:218]">e</span> <span _mstdst="0_220:226" _mstsrc="0_203:209" id="Dst[0][203:209:220:226]">i formati</span> <span _mstdst="0_228:228" _mstsrc="0_211:213" id="Dst[0][211:213:228:228]">e</span> <span _mstdst="0_230:232" _mstsrc="0_215:217" id="Dst[0][215:217:230:232]">può</span> <span _mstdst="0_234:239" _mstsrc="0_219:220" id="Dst[0][219:220:234:239]">essere</span> <span _mstdst="0_241:250" _mstsrc="0_222:225" id="Dst[0][222:225:241:250]">utilizzata</span> <span _mstdst="0_252:254" _mstsrc="0_227:228" id="Dst[0][227:228:252:254]">per</span> <span _mstdst="0_256:261" _mstsrc="0_244:248" id="Dst[0][244:248:256:261]">creare</span> <span _mstdst="0_263:277" _mstsrc="0_230:242" id="Dst[0][230:242:263:277]">automaticamente</span> <span _mstdst="0_279:292" _mstsrc="0_257:265" id="Dst[0][257:265:279:292]">un'interfaccia</span> <span _mstdst="0_294:299" _mstsrc="0_252:255" id="Dst[0][252:255:294:299]">utente</span> <span _mstdst="0_301:303" _mstsrc="0_267:268" id="Dst[0][267:268:301:303]">per</span> <span _mstdst="0_305:313" _mstsrc="0_270:276" id="Dst[0][270:276:305:313]">acquisire</span> <span _mstdst="0_315:315" _mstsrc="0_278:280" id="Dst[0][278:280:315:315]">i</span> <span _mstdst="0_317:322" _mstsrc="0_292:297" id="Dst[0][292:297:317:322]">valori</span> di <span _mstdst="0_327:335" _mstsrc="0_282:290" id="Dst[0][282:290:327:335]">parametro</span> <span _mstdst="0_337:338" _mstsrc="0_302:303" id="Dst[0][302:303:337:338]">da</span> <span _mstdst="0_340:349" _mstsrc="0_305:308" id="Dst[0][305:308:340:349]">utilizzare</span> <span _mstdst="0_351:353" _mstsrc="0_310:311" id="Dst[0][310:311:351:353]">per</span> <span _mstdst="0_355:362" _mstsrc="0_313:319" id="Dst[0][313:319:355:362]">eseguire</span> <span _mstdst="0_364:365" _mstsrc="0_321:321" id="Dst[0][321:321:364:365]">un</span> <span _mstdst="0_367:374" _mstsrc="0_323:329" id="Dst[0][323:329:367:374]">processo</span>.<br />
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">Come per il getCapabilities l'implementazione deve supportare l'operazione di </span><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><span _mstdst="0_16:30" _mstsrc="0_4:18" id="Dst[0][4:18:16:30]">DescribeProcess</span> <span _mstdst="0_32:39" _mstsrc="0_30:35" id="Dst[0][30:35:32:39]"></span>via HTTP GET mentre il supporto HTTP POST è opzionale.</span><br />
<div name="div[0]">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><br /></span></div>
<div name="div[0]">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">Via
HTTP GET possiamo fornire i parametri di richiesta come KVP (Key Value
Pair) codificate. Nel nostro esempio (ho inserito solo le KVP
obbligatorie):</span></div>
<div name="div[0]" style="text-align: center;">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">http://wms.pcn.minambiente.it/wps?service=wps&request=DescribeProcess&version=1.0.0&identifier=TransformCoordinates</span><br />
<div style="text-align: left;">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">oppure</span></div>
<div style="text-align: center;">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">http://wms.pcn.minambiente.it/wps?service=wps&request=DescribeProcess&version=1.0.0&identifier=ALL</span></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">Con il primo desideriamo visualizzare il processo nominato </span><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">TransformCoordinates mentre utilizzando ALL desideriamo listare tutti i processi. Comunque nel caso specifico ne abbiamo solo uno (</span></span><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">TransformCoordinates</span>).</span></span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">Qui potete vederla <a href="http://sit2.sistemigis.it/sit/rest/services/Demo/WPS/MapServer/exts/UtilityWPSSOE/wctsPCN?request=DescribeProcess&geometries=&export=&sourceCRS=&targetCRS=&f=html" target="_blank">live</a>. </span> </span></div>
</div>
<br />
Infine l'operazione di Execute <span _mstdst="0_27:34" _mstsrc="0_22:27" id="Dst[0][22:27:27:34]">permette</span> <span _mstdst="0_36:41" _mstsrc="0_33:39" id="Dst[0][33:39:36:41]">al client</span> <span _mstdst="0_43:45" _mstsrc="0_29:31" id="Dst[0][29:31:43:45]">WPS</span> di <span _mstdst="0_47:54" _mstsrc="0_44:46" id="Dst[0][44:46:47:54]">eseguire</span> <span _mstdst="0_56:57" _mstsrc="0_48:48" id="Dst[0][48:48:56:57]">un</span> <span _mstdst="0_59:66" _mstsrc="0_60:66" id="Dst[0][60:66:59:66]">processo</span> <span _mstdst="0_68:78" _mstsrc="0_50:58" id="Dst[0][50:58:68:78]">specifico</span> <span _mstdst="0_80:91" _mstsrc="0_68:78" id="Dst[0][68:78:80:91]">implementato</span> <span _mstdst="0_93:94" _mstsrc="0_80:81" id="Dst[0][80:81:93:94]">da</span>l <span _mstdst="0_99:104" _mstsrc="0_85:90" id="Dst[0][85:90:99:104]">server</span>, <span _mstdst="0_107:117" _mstsrc="0_93:97" id="Dst[0][93:97:107:117]">utilizzando</span> <span _mstdst="0_119:119" _mstsrc="0_99:101" id="Dst[0][99:101:119:119]">i</span> <span _mstdst="0_121:126" _mstsrc="0_119:124" id="Dst[0][119:124:121:126]">valori</span> di <span _mstdst="0_131:139" _mstsrc="0_109:117" id="Dst[0][109:117:131:139]">parametro</span> di <span _mstdst="0_144:148" _mstsrc="0_103:107" id="Dst[0][103:107:144:148]">input</span> <span _mstdst="0_150:156" _mstsrc="0_126:133" id="Dst[0][126:133:150:156]">forniti</span> <span _mstdst="0_158:158" _mstsrc="0_135:137" id="Dst[0][135:137:158:158]">e</span> <span _mstdst="0_160:170" _mstsrc="0_139:147" id="Dst[0][139:147:160:170]">restituendo</span> <span _mstdst="0_172:172" _mstsrc="0_149:151" id="Dst[0][149:151:172:172]">i</span> <span _mstdst="0_174:179" _mstsrc="0_160:165" id="Dst[0][160:165:174:179]">valori</span> di <span _mstdst="0_184:189" _mstsrc="0_153:158" id="Dst[0][153:158:184:189]">output</span> <span _mstdst="0_191:198" _mstsrc="0_167:174" id="Dst[0][167:174:191:198]">prodotti</span>. Gli <span _mstdst="0_201:208" _mstsrc="0_177:182" id="Dst[0][177:182:201:208]">Input</span> <span _mstdst="0_210:216" _mstsrc="0_184:186" id="Dst[0][184:186:210:216]">possono</span> <span _mstdst="0_218:223" _mstsrc="0_188:189" id="Dst[0][188:189:218:223]">essere</span> <span _mstdst="0_225:231" _mstsrc="0_191:198" id="Dst[0][191:198:225:231]">inclusi</span> <span _mstdst="0_233:244" _mstsrc="0_200:207" id="Dst[0][200:207:233:244]">direttamente</span> <span _mstdst="0_246:250" _mstsrc="0_209:210" id="Dst[0][209:210:246:250]">nella</span> <span _mstdst="0_252:260" _mstsrc="0_224:230" id="Dst[0][224:230:252:260]">richiesta</span> <span _mstdst="0_262:268" _mstsrc="0_216:222" id="Dst[0][216:222:262:268]">Execute</span>, <span _mstdst="0_271:271" _mstsrc="0_233:234" id="Dst[0][233:234:271:271]">o</span> mediante riferimenti web.<br />
Per l'operazione di Execute l'implementazione dell'HTTP POST è obbligatoria mentre è facoltativa quella dell'HTTP GET.<br />
I parametri di ingresso sono l'Identifier (<span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]"><span _mstdst="0_177:191" _mstsrc="0_164:177" id="Dst[0][164:177:177:191]">TransformCoordinate), il SourceCRS, il TargetCRS e l'InputData. Per il SourceCRS e TargetCRS occorre visualizzare l'elenco fornito dalla richiesta di DescribeProcess mentre per l'InputData occorre passare i dati in formato GML nelle versioni supportate indicate sempre nella richiesta di DescribeProcess.</span></span><br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13;"><span style="color: #2b91af;"> XElement</span> root = <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(
<span style="color: #2b91af;">Global</span>.wps + <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">RequestWPS</span>), <span style="color: #2b91af;">RequestWPS</span>.Execute),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"ows"</span>, <span style="color: #2b91af;">Global</span>.ows.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"wps"</span>, <span style="color: #2b91af;">Global</span>.wps.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"xlink"</span>, <span style="color: #2b91af;">Global</span>.xlink.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"xsi"</span>, <span style="color: #2b91af;">Global</span>.xsi.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">Global</span>.xsi + <span style="color: #a31515;">"schemaLocation"</span>, <span style="color: #2b91af;">Global</span>.schemaLocation.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #2b91af;">XNamespace</span>.Xmlns + <span style="color: #a31515;">"gml"</span>, <span style="color: #2b91af;">Global</span>.gml.NamespaceName),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"service"</span>, <span style="color: #2b91af;">Global</span>.serviceWPS),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"version"</span>, <span style="color: #2b91af;">Global</span>.versionWPS),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Identifier"</span>, <span style="color: blue;">this</span>.wctsPCNIdentifier),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"DataInputs"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Input"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Identifier"</span>, <span style="color: #a31515;">"SourceCRS"</span>), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Data"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"LiteralData"</span>, sourceCRSValue))), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Input"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Identifier"</span>, <span style="color: #a31515;">"TargetCRS"</span>), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Data"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"LiteralData"</span>, targetCRSValue))), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Input"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Identifier"</span>, <span style="color: #a31515;">"TestTransformation"</span>), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Data"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"LiteralData"</span>, <span style="color: #a31515;">"false"</span>))), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Input"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Identifier"</span>, <span style="color: #a31515;">"InputData"</span>), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"Data"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"ComplexData"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"mimeType"</span>, <span style="color: #a31515;">"text/xml; subtype=gml/3.1.1"</span>), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"MultiGeometry"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"srsName"</span>, sourceCRSValue)))))),
<span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"ResponseForm"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.wps + <span style="color: #a31515;">"RawDataOutput"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"mimeType"</span>, <span style="color: #a31515;">"text/xml; subtype=gml/3.1.1"</span>), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.ows + <span style="color: #a31515;">"Identifier"</span>, <span style="color: #a31515;">"TransformedData"</span>))));
<span style="color: #2b91af;">XDocument</span> xDoc = <span style="color: blue;">new</span> <span style="color: #2b91af;">XDocument</span>(<span style="color: blue;">new</span> <span style="color: #2b91af;">XDeclaration</span>(<span style="color: #2b91af;">Global</span>.versionXML, <span style="color: #2b91af;">Encoding</span>.UTF8.WebName, <span style="color: blue;">null</span>), root);
<span style="color: #2b91af;">XElement</span> xElementMultiGeometry = xDoc.Descendants(<span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"MultiGeometry"</span>).First();
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">IGeometry</span> geometry <span style="color: blue;">in</span> geometries)
{
<span style="color: blue;">if</span> (geometry <span style="color: blue;">is</span> <span style="color: #2b91af;">IPoint</span>)
{
<span style="color: #2b91af;">IPoint</span> point = geometry <span style="color: blue;">as</span> <span style="color: #2b91af;">IPoint</span>;
xElementMultiGeometry.Add(<span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"geometryMember"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"Point"</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">XAttribute</span>(<span style="color: #a31515;">"srsName"</span>, sourceCRSValue), <span style="color: blue;">new</span> <span style="color: #2b91af;">XElement</span>(<span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"coordinates"</span>, <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"{0},{1}"</span>, point.X.ToString(<span style="color: #2b91af;">Global</span>.CultureUS), point.Y.ToString(<span style="color: #2b91af;">Global</span>.CultureUS))))));
}
}
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> mem = <span style="color: blue;">new</span> <span style="color: #2b91af;">MemoryStream</span>())
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> writer = <span style="color: blue;">new</span> <span style="color: #2b91af;">XmlTextWriter</span>(mem, <span style="color: #2b91af;">Encoding</span>.UTF8))
{
writer.Formatting = <span style="color: #2b91af;">Formatting</span>.Indented;
xDoc.WriteTo(writer);
writer.Flush();
mem.Flush();
mem.Seek(0, <span style="color: #2b91af;">SeekOrigin</span>.Begin);
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> reader = <span style="color: blue;">new</span> <span style="color: #2b91af;">StreamReader</span>(mem))
{
<span style="color: blue;">string</span> xml = reader.ReadToEnd();
<span style="color: #2b91af;">XDocument</span> xDocument = <span style="color: blue;">this</span>.ResponseWCTSPCN(xml);
<span style="color: blue;">var</span> result = xDocument.Elements().Where(k => (k.Name == <span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"MultiGeometry"</span>)).Elements().Where(h => (h.Name == <span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"geometryMember"</span>));
<span style="color: #2b91af;">IList</span><<span style="color: #2b91af;">IPoint</span>> points = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">IPoint</span>>();
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> e <span style="color: blue;">in</span> result)
{
<span style="color: #2b91af;">XElement</span> xElement = e.Elements().Where(x => (x.Name == <span style="color: #2b91af;">Global</span>.gml + <span style="color: #a31515;">"Point"</span>)).ElementAtOrDefault(0);
<span style="color: blue;">string</span>[] xy = xElement.Value.Split(<span style="color: blue;">new</span> <span style="color: blue;">char</span>[] { <span style="color: #a31515;">' '</span> });
<span style="color: #2b91af;">IPoint</span> point = <span style="color: blue;">new</span> <span style="color: #2b91af;">PointClass</span>();
point.PutCoords(<span style="color: #2b91af;">Convert</span>.ToDouble(xy[0], <span style="color: #2b91af;">Global</span>.CultureUS), <span style="color: #2b91af;">Convert</span>.ToDouble(xy[1], <span style="color: #2b91af;">Global</span>.CultureUS));
points.Add(point);
}</pre>
...<br />
<br />
<br />
Qui potete vederla <a href="http://sit2.sistemigis.it/sit/rest/services/Demo/WPS/MapServer/exts/UtilityWPSSOE/wctsPCN?request=Execute&geometries=%5B%7B%22x%22+%3A+1498540.015%2C+%22y%22+%3A+5036312.823%7D%2C%7B%22x%22+%3A+1497540.015%2C+%22y%22+%3A+5037312.823%7D%5D%0D%0A&export=false&sourceCRS=urn%3Aogc%3Adef%3Acrs%3AEPSG%3A6.12%3A3003&targetCRS=urn%3Aogc%3Adef%3Acrs%3AEPSG%3A6.12%3A4326&f=html" target="_blank">live</a> mentre qui potete vedere l'<a href="http://sit2.sistemigis.it/sit/rest/services/Demo/WPS/MapServer/exts/UtilityWPSSOE/Help" target="_blank">help</a>.<br />
<br />
<br />
<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-65597545038816398722013-10-31T12:42:00.000+01:002013-11-04T12:44:37.117+01:00OAuth 2 Da marzo 2013 ArcGIS Online ha introdotto nuove ArcGIS API basate su OAuth 2 per la gestione delle login degli utenti e delle app; OAuth 2 è disponibile per ArcGIS Online mentre non ancora per Portal for ArcGIS.<br />
Ma cos'è OAuth? E' un protocollo di autorizzazione descritto da uno standard aperto che permette ad applicazioni di chiamare in modo sicuro ed autorizzato API messe a disposizione da un servizio Web. Permette di accedere alle risorse protette di un utente senza che esso debba condividere le sue credenziali (username e password). <a href="http://oauth.net/2/" target="_blank">Qui</a> possiamo vedere le specifiche mentre di seguito descriveremo l'implementazione in ArcGIS.<br />
Come sviluppatori, utilizzando la piattaforma ArcGIS possiamo sviluppare i due seguenti tipi di applicazioni:<br />
<ul>
<li>Applicazioni destinate ad utenti finali della piattaforma ArcGIS. Queste applicazioni necessitano di consentire agli utenti di accedere alla piattaforma tramite applicazione. Questi tipi di login sono conosciuti come user login;</li>
<li>applicazioni destinate ad utenti finali che non sono conosciuti alla piattaforma ArcGIS. Queste applicazioni necessitano di accedere alla piattaforma per conto dell'applicazione. Questo tipo di login sono conosciute come app login.</li>
</ul>
Possiamo sviluppare queste app utilizzando Javascript, iOS, Android, Flex e Silverlight. In questo contesto la piattaforma è ArcGIS Online che è disponibile in arcgis.com o utilizzando un ArcGIS Portal disponibile ad uno specifico portal url insieme a tutti i servizi associati.<br />
<h2>
Applicazioni basate su OAuth 2</h2>
Tutte le app che utilizzano OAuth 2 devono essere registrate con la piattaforma ed avere dalla piattaforma assegnato un AppID. Per registrare la nostra applicazione, una volta che accediamo alla piattaforma, utilizzando il nostro account di sviluppatore o dell'organizzazione utilizziamo la funzione 'Aggiungi elemento' in 'I miei contenuti' per aggiungere e registrare la nostra app.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2JaVUqTTreuKoxi8Owyvymrsp9B04XVFzPu4s4Aj1R_v0v-p5wz236V2P9-ezU5KyZK9B42mUqN0mt67ez4ETPEFkduQxqptB-4bgrPghmMWLeB5U2klBJUbABNYgPPzIGjZvWKotNez5/s1600/oauth2_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2JaVUqTTreuKoxi8Owyvymrsp9B04XVFzPu4s4Aj1R_v0v-p5wz236V2P9-ezU5KyZK9B42mUqN0mt67ez4ETPEFkduQxqptB-4bgrPghmMWLeB5U2klBJUbABNYgPPzIGjZvWKotNez5/s640/oauth2_1.png" width="640" /></a></div>
<br />
La registrazione assegna all'applicazione un AppID e un App Secret opzionale.<br />
<br />
<h4>
User login</h4>
User login utilizzano le ArcGIS API basate su OAuth 2 e sono applicazioni che guidano l'utente ad accedere alla piattaforma tramite pagina di login ospitata nella piattaforma ArcGIS.<br />
Questo è comune a tutti i tipi di app: web app su browser, web app server side, app su device o tablet e app desktop. I device, tablet e desktop utilizzeranno controlli browser lato client per integrare questa login all'interno dell'app. L'applicazione riceverà un token di accesso utente che può utilizzare per conto dell'utente per accedere alla piattaforma. Il token di accesso necessita di essere inviato alla piattaforma per tutte le richieste. Utilizzando gli SDK client ArcGIS, l'Identity Manager si prenderà cura di effettuare tutte le richieste con il token mentre lavorando direttamente con le REST API sarà responsabilità dello sviluppatore includere il token per ogni richiesta.<br />
In funzione del tipo di applicazione ci sono delle leggere differenze:<br />
<br />
<strong>User login in app javascript</strong><br />
<br />
Applicazioni su browser devono registrare uno o più <a href="http://it.wikipedia.org/wiki/Uniform_Resource_Identifier" target="_blank">URI</a> redirect quando vengono registrate.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit5GP5PB99xM7x_bCqXm9l5O7HgTVySH9OIlYv1rK1mBW7eC8ITeT4rTtmAj8Op05ppXh1wSWyK9wp4VZ2S2iDSWMi7JWocIW8TABv3CMhGcbyhluMFmC_mcQNiatmcRiZIsc09S-QmdEu/s1600/oauth_2_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="419" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit5GP5PB99xM7x_bCqXm9l5O7HgTVySH9OIlYv1rK1mBW7eC8ITeT4rTtmAj8Op05ppXh1wSWyK9wp4VZ2S2iDSWMi7JWocIW8TABv3CMhGcbyhluMFmC_mcQNiatmcRiZIsc09S-QmdEu/s640/oauth_2_2.png" width="640" /></a></div>
<br />
Questo è l'URI dell'app e al quale sarà restituito il token di accesso.<br />
La user login è effettuata in un singolo passaggio e richiede che l'app indirizzi il browser all'url di autorizzazione OAuth 2 del portale:<br />
<br />
https://www.arcgis.com/sharing/oauth2/authorize?<br />
client_id=APPID&<br />
response_type=token&<br />
redirect_uri=<redirect_uri><br />
<br />
Questo unico passaggio è riferito come una OAuth a concessione implicita. Il redirect_uri passato dalla app in questa richiesta deve essere una superstringa di una delle uri registrate per l'app.<br />
<br />
Se l'utente finale accede con successo alla piattaforma, il server restituisce un token di accesso reindirizzando il browser allo specifico redirect_uri. Il token di accesso è restituito come parte dell'url accodato al redirect _uri.<br />
<br />
Ad esempio, il server può reindirizzare il browser al seguente indirizzo URL:<br />
<br />
<a href="http://app.example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&expires_in=3600">http://app.example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&expires_in=3600</a><br />
<br />
Il token di default è valido per due ore. E' possibile richiedere con questo metodo un token di accesso con un periodo di validità più lungo (in minuti). Il token restituito può essere valido per un periodo più breve in base al periodo massimo di validità impostato dall'organizzazione dell'utente o dalla piattaforma.<br />
<br />
<a href="https://developers.arcgis.com/en/javascript/jssamples/portal_oauth_inline.html" target="_blank">Qui</a> potete vedere un esempio utilizzando le ArcGIS API for Javascript.<br />
<br />
<h4>
User login con app iOS, Android e WPF</h4>
In questo caso è raccomandato un flusso in due passaggi indicato come concessione del codice di autorizzazione.<br />
<br />
<em><strong>Registrazione</strong></em><br />
<br />
Come parte del processo di registrazione, l' app registra un <em>register_uri. </em>Il register_uri può essere o uno speciale valore <span class="usertext"><em><strong>urn:ietf:wg:oauth:2.0:oob</strong></em></span> od uno specifico URI personalizzato per l'applicazione che è gestito dal device. La piattaforma risolve lo speciale URI ad un URL ospitato sulla piattaforma (arcgis.com o portal) che può essere utilizzato dall'applicazione installata per ottenere il codice di autorizzazione alla fine del primo passaggio di autenticazione dell'utente e l'autorizzazione dell'applicazione.<br />
<br />
Applicazioni iOS e Android possono anche registrare un redirect_uri personalizzato che il browser <br />
risolve ad un gestore dell'app eseguita sul device. Un esempio di redirect_uri è <span class="usertext"><strong><em>x-com.mycorp.myapp://oauth.callback. </em></strong>In questo caso il browser direttamente chiama il gestore dell'applicazione alla fine della login user.</span><br />
<span class="usertext"></span><br />
<span class="usertext">La user login viene eseguita in due passaggi: il primo restituisce un codice di autorizzazione e il secondo restituisce il token di accesso.</span><br />
<span class="usertext"></span><br />
<span class="usertext"><strong><em>Codice di autorizzazione</em></strong></span><br />
<br />
Il primo passaggio dell'autenticazione dell'utente è per l'app ottenere un codice di autorizzazione per conto dell'utente. Questo richiede che l'app apra un finestra del browser e indirizzi l'utente al seguente indirizzo:<br />
<br />
https://www.arcgis.com/sharing/oauth2/authorize?<br />
client_id=APPID&<br />
response_type=code&<br />
redirect_uri=<redirect_uri><br />
Il redirect_uri passato è o una speciale stringa (<span class="usertext">urn:ietf:wg:oauth:2.0:oob) per il redirect_uri dell'ArcGIS ospitato o un URI registrato personalizzato dall'app sul device.</span><br />
<span class="usertext"></span><br />
<span class="usertext">Se l'utente con successo presenta le proprie credenziali (username e passowrd) all' authorization server (arcgis.com o un portal) e se l'utente accetta l'identità registrata dell'applicazione corrispondete al client_id, il server restituisce un codice di autorizzazione reindirizzando il browser allo specificato redirect_uri con il codice di autorizzazione aggiunto come un parametro della query string. </span><br />
<span class="usertext"></span><br />
<span class="usertext">Se il valore passato per il redirect_uri è <span class="usertext">urn:ietf:wg:oauth:2.0:oob</span>, l'authorization server (arcgis.com o un portal) reindirizza il browser a <span class="usertext">https://www.arcgis.com/sharing/oauth2/approval</span> o al portal con il codice di autorizzazione disponibile all'applicazione nel titolo della pagina. Per esempio il server può reindirizzare il browser al seguente URL:</span><br />
<br />
https://www.arcgis.com/sharing/oauth2/approval?code=SplxlOBeZQQYbYS6WxSbIA<br />
<br />
Questo speciale URL restituisce il contenuto HTML del titolo che avrà la seguente forma:<br />
<br />
<title>SUCCESS code=Sp1x1OBeZQQYbYS6WxSbIA</title><br />
Spetta all'applicazione che ospita il browser estrarre il codice di autorizzazione dal titolo e chiudere la finestra del browser se il codice non deve essere visualizzato all'utente finale.<br />
<br />
<div id="GUID-BBC423E9-1689-43E0-ACBD-DDD46A2AFCFB">
Se il valore passato al redirect_uri è un URI registrato personalizzato sul device e gestito dall'applicazione, il gestore dell'applicazione è responsabile di ricevere il redirect_uri dal browser e estrarre il codice di autorizzazione dalla query string dell'URL. Ad esempio il server può reindirizzare il browser al seguente URL:</div>
<br />
x-com.mycorp.myapp://oauth.callback?code=SplxlOBeZQQYbYS6WxSbIA<br />
<br />
<a href="http://www.arcgis.com/home/item.html?id=b8e53fb6ae944b19ae8168eafcce9276" target="_blank">Qui</a> potete vedere un esempio con iOS mentre <a href="http://www.arcgis.com/home/item.html?id=1d3beac52f454f78aa1a8bcadaac692a" target="_blank">qui</a> potete vedere un esempio con WPF. Per Android potete invece vedere <a href="http://forums.arcgis.com/threads/92951-OAuth2-and-android" target="_blank">qui</a>: il supporto completo con Android sarà con la versione 10.2 dell'SDK.<br />
<br />
<em><strong>Token di accesso</strong></em><br />
<strong><em></em></strong><br />
Una volta che il codice di autorizzazione è stato ottenuto, l'app deve scambiarlo per un token di accesso. La richiesta è una richiesta POST all'endpoint del token:<br />
<br />
https://www.arcgis.com/sharing/oauth2/token<br />
<br />
e tutti i parametri (nel seguente esempio) devono essere inviati nel corpo della richiesta e non come parte della componente query dell'URI:<br />
<br />
client_id=APPID&<br />
client_secret=APPSECRET&<br />
grant_type=authorization_code&<br />
code=CODICEDIAUTORIZZAZIONE<br />
<br />
La risposta è restituita come oggetto JSON ed include un campo access_token. L'app deve utilizzare questo token quando farà le richieste successive al server. Un esempio di risposta JSON: <br />
<br />
{<br />
"access_token":"2YotnFZFEjr1zCsicMWpAA",<br />
"expires_in": 3600,<br />
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" <br />
}<br />
<br />
L'uso dell'APPSECRET (ouath2 client_secret) in questa richiesta è opzionale nel caso di user login<br />
<br />
L'autenticazione dell'app dalla piattaforma durante la user login è basata sull'accettazione dell'identità dell'app corrispondente all'APPID visualizzata dall'utente.<br />
<br />
I token di accesso sono di breve durata. L'app può prendere un nuovo access_token utilizzando il refresh_token ottenuto precedentemente. La durata del refresh token che è restituita da questa chiamata è controllabile dall'app. Il tempo predefinito di durata per il token aggiornato restituito da questo flusso è di due settimane. <br />
Utilizzando questo flusso puoi richiedere un refresh token che è valido per un periodo più lungo.<br />
Il refresh token che è restituito può essere valido per un periodo più breve di quello della richiesta perché comunque dipende dal massimo tempo di validità impostato a livello dell' organizzazione dell'utente o piattaforma.<br />
<br />
Puoi scambiare un valido refresh_token per un access_token utilizzando lo stesso token endpoint:<br />
<br />
https://www.arcgis.com/sharing/oauth2/token<br />
<br />
I parametri richiesti in questo caso sono il refresh_token precedentemente ottenuto e un grant_type di refresh_token:<br />
<br />
client_id=APPID&<br />
grant_type=refresh_token&<br />
refresh_token=REFRESHTOKENOTTENUTONELPRECEDENTEPASSO<br />
<h4>
User login con PHP, JSP, ASP.NET o altre web app server side</h4>
Una web app server side è un'app dove l'utente interagisce con l'app tramite page web che sono visualizzate in un browser, ma la parte significativa della logica applicativa viene eseguita lato server.<br />
Le web application server side devono registrare uno o più URI di reindirizzamento al momento della registrazione. Questo sarà l'URI dell'app e l'URI al quale sarà restituito il token di accesso dell'utente.<br />
La user login è eseguita in due passi - il primo restituisce il codice di autorizzazione e il secondo restituisce il token di accesso.<br />
<br />
<em><strong>Codice di autorizzazione</strong></em><br />
Il primo passo dell'autenticazione utente è per l'app ottenere un codice di autorizzazione per conto dell'utente. Questo richiede che l'app indirizzi l'utente all'URL di autorizzazione OAuth 2 del portale (in questo esempio è mostrato arcgis.com):<br />
<br />
https://www.arcgis.com/sharing/oauth2/authorize?<br />
client_id=APPID&<br />
response_type=code&<br />
redirect_uri=<redirect_uri><br />
<br />
Se l'utente con successo presenta le credenziali (ad esempio username e password) al server di autorizzazione (arcgis.com) e se l'utente accetta l'identità registrata dell'applicazione, il server restituisce un codice di autorizzazione reindirizzando il browser allo specifico redirect_uri utilizzando una HTTP response redirect allo specifico redirect_uri. Il codice di autorizzazione è messo a disposizione come parametro della query string e può essere accessibile dall'applicazione server-side che esegue il redirect_uri.<br />
Ad esempio il server può reindirizzare il browser al seguente URL:<br />
<br />
<a href="https://app.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA">https://app.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA</a><br />
<br />
L'applicazione in esecuzione a questo URL poi fa una seconda richiesta server side per ottenere un token di accesso in cambio del codice di autorizzazione come descritto nella seguente sezione.<br />
<br />
<strong><em>Token di accesso</em></strong><br />
<br />
Una volta che il codice di autorizzazione è stato ottenuto, l'app ha bisogno di scambiarlo per un token di accesso.<br />
La richiesta è una richiesta POST all'endpoint /token del portale, qui mostrato per arcgis.com:<br />
<br />
https://www.arcgis.com/sharing/oauth2/token<br />
<br />
Tutti i parametri (nel seguente esempio) devono essere inviati nel corpo della richiesta e non come parte della query string dell'URI:<br />
<br />
client_id=APPID&<br />
client_secret=APPSECRET&<br />
grant_type=authorization_code&<br />
code=CODICEOTTENUTONELPRECEDENTEPASSO<br />
<br />
La risposta è restituita come un oggetto JSON e include un campo access_token. L'app deve utilizzare questo token quando farà le successive richieste per accedere alle risorse.<br />
<br />
Un esempio di risposta JSON è come la seguente:<br />
<br />
{<br />
"access_token":"2YotnFZFEjr1zCsicMWpAA",<br />
"token_type":"example",<br />
"expires_in":3600,<br />
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" <br />
}<br />
<br />
Il refresh token può essere utilizzato con i successivi token di accesso. I token di accesso sono di breve durata. L'app può acquisire un nuovo access_token utilizzando il refresh_token ottenuto precedentemente.<br />
La durata del refresh token restituito da questa chiamata è controllabile dall'app. Il valore di default di durata per il refresh token restituito da questo flusso è di due settimane. Utilizzando questo flusso puoi richiedere un refresh token che è valido per un periodo più lungo passando un parametro expiration (in minuti) durante l'autorizzazione. Il refresh token che è restituito può essere valido per un periodo più breve rispetto a quello richiesto perché comunque dipende dal massimo tempo di validità impostato a livello dell'organizzazione dell'utente o piattaforma.<br />
<br />
Per acquisire un valido refresh_token per un access_token utilizzare lo stesso /token endpoint:<br />
<br />
https://www.arcgis.com/sharing/oauth2/token<br />
<br />
I parametri richiesti in questo caso sono il refresh_token precedentemente ottenuto e un grant_type uguale a refresh_token:<br />
<br />
client_id=APPID&<br />
grant_type=refresh_token&<br />
refresh_token=REFRESHTOKENOTTENUTONELPRECEDENTEPASSO<br />
<br />
Restituisce un access_token aggiornato e il refresh_token può essere successivamente utilizzato. Se il refresh_token non è più valido, verrà restituito una risposta di errore e l'app sarà tenuta a richiedere la user login nuovamente.<br />
<h4>
App login</h4>
<div name="div[0]">
<span _mstdst="0_0:11" _mstsrc="0_0:11" class="dhighlight" id="Dst[0][0:11:0:11]">Le applicazioni</span> <span _mstdst="0_13:21" _mstsrc="0_18:23" id="Dst[0][18:23:13:21]">destinate</span> <span _mstdst="0_23:33" _mstsrc="0_29:33" id="Dst[0][29:33:23:33]">ad utenti</span> <span _mstdst="0_35:40" _mstsrc="0_25:27" id="Dst[0][25:27:35:40]">finali</span> <span _mstdst="0_42:44" _mstsrc="0_35:37" id="Dst[0][35:37:42:44]">che</span> non <span _mstdst="0_46:49" _mstsrc="0_39:41" id="Dst[0][39:41:46:49]">sono</span> <span _mstdst="0_51:61" _mstsrc="0_43:49" id="Dst[0][43:49:51:61]">conosciuti</span> d<span _mstdst="0_63:66" _mstsrc="0_51:52" id="Dst[0][51:52:63:66]">alla</span> <span _mstdst="0_68:78" _mstsrc="0_65:72" id="Dst[0][65:72:68:78]">piattaforma</span> <span _mstdst="0_80:85" _mstsrc="0_58:63" id="Dst[0][58:63:80:85]">ArcGIS</span> <span _mstdst="0_87:96" _mstsrc="0_74:76" id="Dst[0][74:76:87:96]">utilizzano</span> app login <span _mstdst="0_128:130" _mstsrc="0_89:90" id="Dst[0][89:90:128:130]">per</span> <span _mstdst="0_132:142" _mstsrc="0_92:98" id="Dst[0][92:98:132:142]">connettersi</span> <span _mstdst="0_144:147" _mstsrc="0_100:101" id="Dst[0][100:101:144:147]">alla</span> <span _mstdst="0_149:159" _mstsrc="0_107:114" id="Dst[0][107:114:149:159]">piattaforma. In questo caso l'applicazione deve utilizzare sia un APPID (OAuth 2 client_id) e un APPSECRET (OAuth 2 client_secret). Sei responsabile di sviluppare l'applicazione in modo che mantenga segreto l'APPSECRET, incluso anche il fatto che utenti 'malevoli' possano scaricare ed analizzare l'applicazione iOS e Android o visualizzare il codice dell'applicazione Javascript utilizzando strumenti di sviluppo. Un'applicazione 'malevole' che ha accesso alle credenziali dell'applicazione (APPID e APPSECRET) può accedere a servizi a pagamento su ArcGIS, che quindi sarà fatturato all'applicazione. Per la maggior parte delle applicazioni javascript, iOS e Android, questo implica il fatto che la app deve avere una componente applicativa server side che mantiene in sicurezza le credenziali applicative ed esegue il lavoro per conto dell'app.</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">La componente applicativa server side che ha accesso alle credenziali dell'applicazione può ottenere un token utilizzando una singola richiesta. Il tipo di grant OAuth 2 impostato è client_credentials. La richiesta di POST è fatta all'endpoint token OAuth 2.</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">Per arcgis.com:</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">https://www.arcgis.com/sharing/oauth2/token</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">Parametri:</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">client_id=APPID&<br />client_secret=APPSECRET&<br />grant_type=client_credentials</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">L'autenticazione eseguita con successo direttamente restituisce una risposta JSON contenente l'accesso token che permette all'applicazione di lavorare con le risorse che sono accessibili all'applicazione stessa (risorse che sono state condivise con l'applicazione). L'utilizzo del client_secret come precedentemente descritto è obbligatorio.</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"><span _mstdst="0_149:159" _mstsrc="0_107:114">La componente applicativa server side che fa questa chiamata può essere un componente personalizzato che ha la sua propria API che 'wrappa' le API della piattaforma ArcGIS ed espone solo quelle funzioni che necessitano alla app.</span></span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">La componente applicativa server side può anche essere un proxy che preserva le firme ArcGIS REST mentre inoltra le chiamate alle API della piattaforma ArcGIS. Questa è l'opzione che deve essere implementata se l'applicazione è sviluppata utilizzando le API client ArcGIS che le firme REST.</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">In entrambi i casi le chiamate fatte dalla componente applicativa server side alla piattaforma ArcGIS hanno bisogno di includere i token di accesso ottenuti dalla componente in cambio delle credenziali dell'applicazione utilizzando la grant client_credentials precedentemente descritta.</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">In entrambi i casi la componente applicativa server side anche ha bisogno di essere messa in sicurezza che solo l'applicazione possa accedere ad essa.</span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">Qui si riporta delle possibili soluzioni per mettere in sicurezza la componente applicativa server-side:</span></div>
<ul>
<li><div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">Per applicazioni che hanno i loro propri utenti autenticati che rimangono sconosciuti alla piattaforma ArcGIS, l'applicazione può restringere l'accesso alla componente applicativa server side per sessioni di utenti autenticati dell'applicazione. Questo sottintende che gli utenti dell'app che sono sviluppatori non sono 'malevoli'. Se si vuole gestire questo caso e verificare l'uso improprio della componente applicativa server side, occorre monitorarli e controllarli;</span></div>
</li>
<li><div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114">applicazioni delle quali gli utenti sono anonimi anche all'applicazione si può restringere la componente applicativa server side ad utenti finali 'umani' utilizzando la tecnologia <a href="http://it.wikipedia.org/wiki/CAPTCHA" target="_blank">CAPTCHA</a>. Ciò richiede che l'applicazione incorpori al suo interno <a href="http://it.wikipedia.org/wiki/CAPTCHA" target="_blank">CAPTCHA</a> nella sua <a href="http://it.wikipedia.org/wiki/User_Experience" target="_blank">user experience</a>;</span></div>
</li>
<li><div name="div[0]">
le applicazioni possono anche limitare la funzionalità esposta dalla componente server side, ponendo restrizioni sull'IP sulla componente app server side e limiti di banda nella componente con valori appropriati. I limiti di banda sono effettivamente delle misure preventive di abuso della componente applicativa server side da codice malevole server side. </div>
</li>
</ul>
<div name="div[0]">
Le tecniche descritte qui sono applicabili a Javascript, Flex e Silverlight come a iOS, Android e dispositivi client simili.</div>
<div name="div[0]">
</div>
<h2 name="div[0]">
Applicazioni non basate su OAuth2</h2>
<div name="div[0]">
Sia ArcGIS Online che Portal for ArcGIS supportano la chiamata REST API <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm" target="_blank">generateToken</a> che può essere utilizzata sia con le credenziali dell'utente ottenute dall'utente che si autentica nella piattaforma tramite l'applicazione o con le credenziali proprie dell'applicazione.</div>
<div name="div[0]">
La chiamata restituisce un token di accesso su una autenticazione avvenuta con successo che poi utilizzerà nelle successive richieste.</div>
<div name="div[0]">
La chiamata al <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm" target="_blank">generateToken</a> deve essere fatta su HTTPS. Tutte le successive richieste che usa il token necessitano di essere fatte su HTTPS se il portale o l'organizzazione per accedere lo dovesse richiedere.</div>
<div name="div[0]">
</div>
<h4 name="div[0]">
User login </h4>
<div name="div[0]">
Applicazioni che implementano user login basate sulla chiamata al <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm" target="_blank">generateToken</a> sono responsabili di presentare all'utente finale una finestra di dialogo di login per le credenziali dell'utente. L'applicazione è responsabile di mantenere le credenziali dell'utente in sicurezza e trasmetterle su HTTPS.</div>
<div name="div[0]">
</div>
<div name="div[0]">
E' comunque consigliabile utilizzare l'appropriato client SDK per connettersi ed autenticarsi con ArcGIS Online piuttosto che fare chiamate dirette alle REST API. Eseguire connessioni e autenticazioni tramite SDK client ti libera dai dettagli dell'autenticazione così come la gestione delle credenziali dell'utente durante il processo di autenticazione. Un esempio è l'utilizzo dell'IdentityManager dijit che consente all'utente di accedere ai propri account ArcGIS Online o a Portal for ArcGIS, e le successive chiamate sono fatte automaticamente utilizzando il client session e esri.request automaticamente.</div>
<div name="div[0]">
</div>
<div name="div[0]">
Queste sono le limitazioni di implementare la user login non su OAuth2:</div>
<ul>
<li><div name="div[0]">
L'identità dell'app rimane sconosciuta alla piattaforma;</div>
</li>
<li><div name="div[0]">
gli utenti non possono accedere al provider di identità federata che sono accessibili tramite pagine di login ospitate nella piattaforma esposte via API OAuth 2 </div>
</li>
</ul>
<h4 name="div[0]">
App login </h4>
<div name="div[0]">
<span _mstdst="0_0:1" _mstsrc="0_0:0" id="Dst[0][0:0:0:1]">Per l'</span><span _mstdst="0_3:8" _mstsrc="0_2:5" id="Dst[0][2:5:3:8]">utente</span> <span _mstdst="0_10:24" _mstsrc="0_7:18" class="dhighlight" id="Dst[0][7:18:10:24]">che rappresenta</span> <span _mstdst="0_26:39" _mstsrc="0_24:26" id="Dst[0][24:26:26:39]">l'applicazione</span> <span _mstdst="0_41:44" _mstsrc="0_28:32" id="Dst[0][28:32:41:44]">deve</span> <span _mstdst="0_46:51" _mstsrc="0_37:38" id="Dst[0][37:38:46:51]">essere</span> fornito <span _mstdst="0_82:83" _mstsrc="0_57:57" id="Dst[0][57:57:82:83]">un</span> <span _mstdst="0_85:88" _mstsrc="0_64:67" id="Dst[0][64:67:85:88]">nome</span> <span _mstdst="0_90:95" _mstsrc="0_59:62" id="Dst[0][59:62:90:95]">utente</span> <span _mstdst="0_97:99" _mstsrc="0_69:72" id="Dst[0][69:72:97:99]">(ad</span> <span _mstdst="0_101:107" _mstsrc="0_74:81" id="Dst[0][74:81:101:107]">esempio</span>, <span _mstdst="0_110:113" _mstsrc="0_84:96" id="Dst[0][84:96:110:113]">app-</span><span _mstdst="0_114:125" _mstsrc="0_84:96" id="Dst[0][84:96:114:125]">username)</span> <span _mstdst="0_127:127" _mstsrc="0_98:100" id="Dst[0][98:100:127:127]">e</span> <span _mstdst="0_129:136" _mstsrc="0_102:109" id="Dst[0][102:109:129:136]">password</span> <span _mstdst="0_138:141" _mstsrc="0_111:114" id="Dst[0][111:114:138:141]">(ad </span><span _mstdst="0_143:149" _mstsrc="0_116:123" id="Dst[0][116:123:143:149]">esempio</span>, <span _mstdst="0_152:165" _mstsrc="0_126:139" id="Dst[0][126:139:152:165]">app-password).</span> <span _mstdst="0_167:170" _mstsrc="0_141:144" id="Dst[0][141:144:167:170]">App</span> <span _mstdst="0_172:180" _mstsrc="0_146:154" id="Dst[0][146:154:172:180]">destinate</span> <span _mstdst="0_182:192" _mstsrc="0_156:160" id="Dst[0][156:160:182:192]">ad utenti</span> <span _mstdst="0_194:204" _mstsrc="0_162:168" id="Dst[0][162:168:194:204]">sconosciuti</span> <span _mstdst="0_206:209" _mstsrc="0_170:171" id="Dst[0][170:171:206:209]">alla</span> <span _mstdst="0_211:221" _mstsrc="0_177:184" id="Dst[0][177:184:211:221]">piattaforma</span> <span _mstdst="0_223:225" _mstsrc="0_186:188" id="Dst[0][186:188:223:225]">possono</span> <span _mstdst="0_227:234" _mstsrc="0_190:192" id="Dst[0][190:192:227:234]">accedere</span> <span _mstdst="0_236:246" _mstsrc="0_197:201" id="Dst[0][197:201:236:246]">utilizzando</span> <span _mstdst="0_248:253" _mstsrc="0_203:206" id="Dst[0][203:206:248:253]">queste</span> <span _mstdst="0_255:266" _mstsrc="0_208:219" id="Dst[0][208:219:255:266]">app-username</span> <span _mstdst="0_268:268" _mstsrc="0_221:223" id="Dst[0][221:223:268:268]">e</span> app-<span _mstdst="0_270:281" _mstsrc="0_225:236" id="Dst[0][225:236:270:281]">password</span> <span _mstdst="0_283:285" _mstsrc="0_238:241" id="Dst[0][238:241:283:285]">con</span> la chiamata al <span _mstdst="0_295:307" _mstsrc="0_247:259" id="Dst[0][247:259:295:307]"><a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm" target="_blank">generateToken</a></span>. <span _mstdst="0_314:314" _mstsrc="0_271:274" id="Dst[0][271:274:314:314]">È</span> <span _mstdst="0_316:329" _mstsrc="0_286:299" id="Dst[0][286:299:316:329]">responsabilità</span> <span _mstdst="0_331:338" _mstsrc="0_280:284" id="Dst[0][280:284:331:338]">dell'app</span> <span _mstdst="0_344:352" _mstsrc="0_304:307" id="Dst[0][304:307:344:352]">mantenere</span> <span _mstdst="0_354:367" _mstsrc="0_313:324" id="Dst[0][313:324:354:367]">l'app-username</span> <span _mstdst="0_369:369" _mstsrc="0_326:328" id="Dst[0][326:328:369:369]">e</span> <span _mstdst="0_371:382" _mstsrc="0_330:341" id="Dst[0][330:341:371:382]">l'app-password</span> in sicurezza utilizzando <span _mstdst="0_397:402" _mstsrc="0_368:371" id="Dst[0][368:371:397:402]">codice</span> <span _mstdst="0_404:407" _mstsrc="0_363:366" id="Dst[0][363:366:404:407]">lato</span> <span _mstdst="0_409:414" _mstsrc="0_356:361" id="Dst[0][356:361:409:414]">server</span> <span _mstdst="0_416:416" _mstsrc="0_373:374" id="Dst[0][373:374:416:416]">o</span> con <span _mstdst="0_418:419" _mstsrc="0_376:376" id="Dst[0][376:376:418:419]">un</span> <span _mstdst="0_421:426" _mstsrc="0_390:393" id="Dst[0][390:393:421:426]">flusso</span> <span _mstdst="0_431:434" _mstsrc="0_385:388" id="Dst[0][385:388:431:434]">lato</span> <span _mstdst="0_436:441" _mstsrc="0_378:383" id="Dst[0][378:383:436:441]">server</span>.</div>
<div name="div[0]">
</div>
<div name="div[0]">
Le limitazione di implementazione di app login in questo modo sono le seguenti:</div>
<ul>
<li><div name="div[0]">
L'identità dell'app è modellata tramite un utente surrogato;</div>
</li>
<li><div name="div[0]">
non c'è una chiara separazione degli utenti dalle app nella piattaforma.</div>
</li>
</ul>
<div name="div[0]">
</div>
<div name="div[0]">
</div>
<h2 name="div[0]">
Lavorare con i portal ArcGIS</h2>
<div name="div[0]">
Gli esistenti portal come già detto non supportano OAuth 2. Supportano una singola chiamata a <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm" target="_blank">generateToken</a> delle API che restituisce il token di accesso.</div>
<div name="div[0]">
Pertanto le applicazioni dovrebbero continuare ad utilizzare il modello di autenticazione delle applicazioni non basate su OAuth 2 sia per le user login che per le app login.</div>
<div name="div[0]">
Come già detto il modo consigliato è quello di utilizzare l'appropriato Identity Manager dell'SDK.</div>
<div name="div[0]">
Una volta che è stato ottenuto un token di accesso per il portal, l'applicazione può ottenere un token di accesso per i server federati con il portal utilizzando la richiesta <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm" target="_blank">generateToken</a> con il parametro serverURL.</div>
<div name="div[0]">
Se il portal in oggetto utilizza per la sicurezza HTTP, Windows Integrated o basata su PKI anziché utilizzare l'autenticazione basata su token, <span _mstdst="0_0:1" _mstsrc="0_0:2" id="Dst[0][0:2:0:1]">la</span> <span _mstdst="0_3:10" _mstsrc="0_4:11" class="dhighlight" id="Dst[0][4:11:3:10]">risposta</span> <span _mstdst="0_12:14" _mstsrc="0_13:14" id="Dst[0][13:14:12:14]">al</span><span _mstdst="0_16:17" _mstsrc="0_16:18" id="Dst[0][16:18:16:17]">la</span> <span _mstdst="0_19:27" _mstsrc="0_35:43" id="Dst[0][35:43:19:27]">richiesta</span> di <span _mstdst="0_32:45" _mstsrc="0_20:33" id="Dst[0][20:33:32:45]">autenticazione</span> <span _mstdst="0_47:49" _mstsrc="0_50:52" id="Dst[0][50:52:47:49]">del</span> <span _mstdst="0_51:56" _mstsrc="0_54:59" id="Dst[0][54:59:51:56]">server</span> <span _mstdst="0_58:67" _mstsrc="0_61:65" id="Dst[0][61:65:58:67]">necessita </span><span _mstdst="0_69:70" _mstsrc="0_67:68" id="Dst[0][67:68:69:70]">di</span> <span _mstdst="0_72:77" _mstsrc="0_70:71" id="Dst[0][70:71:72:77]">essere</span> <span _mstdst="0_79:85" _mstsrc="0_73:79" id="Dst[0][73:79:79:85]">gestita</span> <span _mstdst="0_87:97" _mstsrc="0_81:85" id="Dst[0][81:85:87:97]">utilizzando</span> <span _mstdst="0_99:100" _mstsrc="0_87:89" id="Dst[0][87:89:99:100]">lo</span> <span _mstdst="0_102:106" _mstsrc="0_112:116" id="Dst[0][112:116:102:106]">stack</span> di <span _mstdst="0_111:123" _mstsrc="0_98:110" id="Dst[0][98:110:111:123]">comunicazione</span> <span _mstdst="0_125:130" _mstsrc="0_91:96" id="Dst[0][91:96:125:130]">nativa</span> <span _mstdst="0_132:136" _mstsrc="0_118:119" id="Dst[0][118:119:132:136]">della</span> <span _mstdst="0_138:148" _mstsrc="0_132:139" id="Dst[0][132:139:138:148]">piattaforma</span> <span _mstdst="0_150:155" _mstsrc="0_125:130" id="Dst[0][125:130:150:155]">client</span>.</div>
<div name="div[0]">
</div>
<h2 name="div[0]">
</h2>
<h2 name="div[0]">
Lavorare con gli ArcGIS Server</h2>
<div name="div[0]">
</div>
<div name="div[0]">
Server ArcGIS che non sono affiliati con ArcGIS Online o Portal for ArcGIS non supportano OAuth 2; supportano una singola chiamata a <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm" target="_blank">generateToken</a> delle API che restituisce il token di accesso.</div>
<div name="div[0]">
Le applicazioni dovrebbero continuare ad utilizzare il modello di autenticazione delle applicazioni non basate su OAuth 2 sia per le user login che per le app login. </div>
<div name="div[0]">
Come già detto il modo consigliato è quello di utilizzare l'appropriato Identity Manager dell'SDK.</div>
<div name="div[0]">
Se il server in oggetto utilizza per la sicurezza HTTP, Windows Integrated o basata su PKI anziché utilizzare l'autenticazione basata su token, <span _mstdst="0_0:1" _mstsrc="0_0:2" id="Dst[0][0:2:0:1]">la</span> <span _mstdst="0_3:10" _mstsrc="0_4:11" class="dhighlight" id="Dst[0][4:11:3:10]">risposta</span> <span _mstdst="0_12:14" _mstsrc="0_13:14" id="Dst[0][13:14:12:14]">al</span><span _mstdst="0_16:17" _mstsrc="0_16:18" id="Dst[0][16:18:16:17]">la</span> <span _mstdst="0_19:27" _mstsrc="0_35:43" id="Dst[0][35:43:19:27]">richiesta</span> di <span _mstdst="0_32:45" _mstsrc="0_20:33" id="Dst[0][20:33:32:45]">autenticazione</span> <span _mstdst="0_47:49" _mstsrc="0_50:52" id="Dst[0][50:52:47:49]">del</span> <span _mstdst="0_51:56" _mstsrc="0_54:59" id="Dst[0][54:59:51:56]">server</span> <span _mstdst="0_58:67" _mstsrc="0_61:65" id="Dst[0][61:65:58:67]">necessita </span><span _mstdst="0_69:70" _mstsrc="0_67:68" id="Dst[0][67:68:69:70]">di</span> <span _mstdst="0_72:77" _mstsrc="0_70:71" id="Dst[0][70:71:72:77]">essere</span> <span _mstdst="0_79:85" _mstsrc="0_73:79" id="Dst[0][73:79:79:85]">gestita</span> <span _mstdst="0_87:97" _mstsrc="0_81:85" id="Dst[0][81:85:87:97]">utilizzando</span> <span _mstdst="0_99:100" _mstsrc="0_87:89" id="Dst[0][87:89:99:100]">lo</span> <span _mstdst="0_102:106" _mstsrc="0_112:116" id="Dst[0][112:116:102:106]">stack</span> di <span _mstdst="0_111:123" _mstsrc="0_98:110" id="Dst[0][98:110:111:123]">comunicazione</span> <span _mstdst="0_125:130" _mstsrc="0_91:96" id="Dst[0][91:96:125:130]">nativa</span> <span _mstdst="0_132:136" _mstsrc="0_118:119" id="Dst[0][118:119:132:136]">della</span> <span _mstdst="0_138:148" _mstsrc="0_132:139" id="Dst[0][132:139:138:148]">piattaforma</span> <span _mstdst="0_150:155" _mstsrc="0_125:130" id="Dst[0][125:130:150:155]">client</span>.</div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"> </span></div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"></span> </div>
<div name="div[0]">
<span _mstdst="0_149:159" _mstsrc="0_107:114"> </span></div>
<br />
<br />
<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-5546735321365250052013-09-30T14:23:00.000+02:002013-10-16T14:24:55.065+02:00CityEngine Web SceneNel post del mese scorso ci eravamo lasciati descrivendo la possibilità di visualizzare le multipatch utilizzando il web viewer Esri (<a href="http://www.arcgis.com/home/item.html?id=38fede3935a440e49cf316dcae6aae47" target="_blank">Esri CityEngine Web Scene</a>) esportando il documento ArcScene nel formato 3ws. Ma che cos'è il visualizzatore Web CityEngine? E' un'applicazione Web per visualizzare scene 3D in un browser. Esso si basa su <a href="http://en.wikipedia.org/wiki/WebGL" target="_blank">WebGL</a> (<em>Web-based Graphics Library) </em>e consente di visualizzare contenuti 3D in un browser attivando l'accelerazione hardware per il rendering degli elementi grafici 3D e senza installare plug-in aggiuntivi. I principali browser supportano WebGL anche se Internet Explorer necessita di <a href="http://www.google.com/chromeframe?quickenable=true" target="_blank">Google Chrome Frame</a>; con il rilascio di <a href="http://msdn.microsoft.com/it-it/library/ie/bg182648(v=vs.85).aspx" target="_blank">IE 11</a> anche il browser di Microsoft supporterà WebGL. Per prestazioni ottimali occorre avere una buona scheda grafica installata per poter sfruttare la potenza di calcolo offerta dalla GPU. Il consiglio è anche di mantenere aggiornati i driver della scheda grafica.<br />
In attesa delle <a href="http://proceedings.esri.com/library/userconf/devsummit13/papers/devsummit-037.pdf" target="_blank">Esri API 3D javascript</a> schedulate per il 1Q del 2014 in versione beta e per il 2Q del 2014 in versione finale, possiamo visualizzare e generare contenuti dinamici 3D anche con il visualizzatore Web CityEngine. <br />
Va ricordato che questo visualizzatore era nato per visualizzare le scene create con <a href="http://www.esri.com/software/cityengine" target="_blank">Esri CityEngine</a>.<br />
<div id="GUID-7DA40072-9EBD-4194-8973-1BE2A09A7E55">
<a class="xref" esrisubtype="extrel" href="http://www.esri.com/software/cityengine" target="_blank">Esri CityEngine</a> è un pacchetto software che consente di creare in modo efficace paesaggi urbani 3D utilizzando i dati GIS esistenti, nonché eseguire geoprogettazioni concettuali in 3D. Una volta modificato il paesaggio, la scena 3D può essere caricata anche direttamente in <span ishcondition="agol_plat=web" purpose="ph">ArcGIS Online per condividerla </span>con altri utenti tramite un browser Web. Ma, come già detto dalla 10.2, è possibile esportare scene web 3D da documenti ArcScene in formato scena Web di CityEngine senza la necessità di avere una licenza CityEngine ma quella di avere la licenza dell'estensione 3D Analyst per ArcGIS.</div>
Una delle possibili applicazioni in questo panorama potrebbe essere quella di generare dinamicamente contenuti 3D, ad esempio, feature Multipatch, feature class PolylineZ, feature class PointZ, con simboli 3D, caricarli in un documento ArcScene ed esportare la scena da far visualizzare nel viewer Esri WebGL compliant.<br />
Ad esempio prendiamo uno dei tanti tool geoprocessing 3D che ArcGIS ci mette a disposizione: <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//00q900000056000000" target="_blank">skyline</a> e relativa <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#/Skyline_Barrier/00q90000006q000000/" target="_blank">skyline barrier</a>. Potremmo generare le feature class e caricarle al volo in un sxd per generare la scene. Le skyline sono utilizzate per, ad esempio, <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//00q80000004r000000" target="_blank">analizzare gli spazi aerei</a>, per le valutazioni di impatto ambientale e a supporto di altre analisi.<br />
<br />
Qui possiamo vedere un esempio:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRYXUlhroE-nFE8rRqU8cz6Wrbrey7rx8RX_6zgh6mfRVmE0mH_7LOsgyH6cYUNMXHTt2IUxZ10jfg_NraCWA13uf2RT1R72OpCGaD0MG4bEmL-r_UeEEfH4yye008e64U3NpdWE-Tujjs/s1600/skyline2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="411" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRYXUlhroE-nFE8rRqU8cz6Wrbrey7rx8RX_6zgh6mfRVmE0mH_7LOsgyH6cYUNMXHTt2IUxZ10jfg_NraCWA13uf2RT1R72OpCGaD0MG4bEmL-r_UeEEfH4yye008e64U3NpdWE-Tujjs/s640/skyline2.png" width="640" /></a></div>
<br />
Ma potremmo anche inserire l'animazione negli specchi d'acqua (water shader) semplicemente aggiungendo al nome del layer un suffisso (per maggiori dettagli vedere <a href="http://forums.arcgis.com/threads/88493-Animated-Water-Shader-in-WebScene" target="_blank">qui</a>).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizSgvs-7U8q15wpiwxNxYRSn-nefZAty3vrrtYxnHLXhiOGE_vR-G5MhW90V4QnRoeXl2a2FlXoYGvAmSHKa155ntEvDckWQNpAi4M6Bg_rlzU53U4G5qe-aN3buxFYWtidkKYBj-BWldA/s1600/skyline1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizSgvs-7U8q15wpiwxNxYRSn-nefZAty3vrrtYxnHLXhiOGE_vR-G5MhW90V4QnRoeXl2a2FlXoYGvAmSHKa155ntEvDckWQNpAi4M6Bg_rlzU53U4G5qe-aN3buxFYWtidkKYBj-BWldA/s640/skyline1.png" width="640" /></a></div>
<br />
<br />
<a href="http://sit2.sistemigis.it/js/skylinevco/" target="_blank">Qui</a> potete vedere una pagina dimostrativa di creazione di una scena generando la skyline e la skyline barrier indicando degli osservatori sulla mappa utilizzando una SOE ArcGis Server. Una volta creata la scene (in questo caso circa 60 secondi) comparirà un toaster in basso a destra con il link della scena.<br />
<br />
Nel tool di skyline possiamo anche indicare anche una o più feature class da utilizzare come ostacoli (tipicamente edifici). In questo caso possiamo impostare osservatori anche sopra gli edifici calcolando la quota tramite l'intersezione dell'IRay con la multipatch.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL-3Inv-9Ewcvn4lFiPLzQrnH7wPOSH1CygrCACjkOcVY3nxST2uuHbX-DkxDTmP6QEU4ptAzyzH545oYwhXUyoLF5W8L9XaKiv7c6_TuWnxwiPLUEBiioFM5LgNFC29gkuEf_9aau-Za-/s1600/skyline4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL-3Inv-9Ewcvn4lFiPLzQrnH7wPOSH1CygrCACjkOcVY3nxST2uuHbX-DkxDTmP6QEU4ptAzyzH545oYwhXUyoLF5W8L9XaKiv7c6_TuWnxwiPLUEBiioFM5LgNFC29gkuEf_9aau-Za-/s320/skyline4.png" width="310" /></a></div>
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: #2b91af;"> IVector3D</span> vector = <span style="color: blue;">new</span> <span style="color: #2b91af;">Vector3DClass</span>();
vector.SetComponents(0, 0, -1);
<span style="color: blue;">int</span> idObserver = 0;
<span style="color: blue;">bool</span> isAddObserver = <span style="color: blue;">false</span>;
<span style="color: blue;">bool</span> isAddOnBuildings;
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">IPoint</span> p <span style="color: blue;">in</span> points)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">if</span> ((p == <span style="color: blue;">null</span>) || (p.IsEmpty))
{
<span style="color: blue;">continue</span>;
}
<span style="color: #2b91af;">IRay</span> ray = <span style="color: blue;">new</span> <span style="color: #2b91af;">RayClass</span>();
ray.Origin = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(p.X, p.Y, 1000000.0);
ray.Vector = vector;
isAddOnBuildings = <span style="color: blue;">false</span>;
<span style="color: blue;">if</span> (featureClassObstacles != <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">IFeatureCursor</span> featureCursor = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
featureCursor = featureClassObstacles.Search(<span style="color: blue;">null</span>, <span style="color: blue;">true</span>);
<span style="color: #2b91af;">IFeature</span> feature = <span style="color: blue;">null</span>;
<span style="color: blue;">while</span> ((feature = featureCursor.NextFeature()) != <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">IGeometry</span> g = feature.ShapeCopy;
<span style="color: blue;">if</span> (ray.Intersects(g))
{
<span style="color: #2b91af;">IPoint</span> firstIntersectionPoint = <span style="color: blue;">new</span> <span style="color: #2b91af;">PointClass</span>();
ray.QueryFirstIntersection(g, firstIntersectionPoint);
<span style="color: blue;">if</span> (!firstIntersectionPoint.IsEmpty)
{
<span style="color: #2b91af;">IFeature</span> featureObserver = featureClassObserver.CreateFeature();
firstIntersectionPoint.Z += offset;
featureObserver.Shape = firstIntersectionPoint;
idObserver++;
featureObserver.set_Value(idxIdObserver, idObserver);
featureObserver.Store();
isAddObserver = <span style="color: blue;">true</span>;
isAddOnBuildings = <span style="color: blue;">true</span>;
<span style="color: blue;">break</span>;
}
}
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
<span style="color: blue;">finally</span>
{
<span style="color: #2b91af;">Marshal</span>.FinalReleaseComObject(featureCursor);
}
}
<span style="color: blue;">if</span> (!isAddOnBuildings)
{
<span style="color: green;">//Get the column and row by giving x,y coordinates in a map space.</span>
<span style="color: blue;">int</span> col = raster.ToPixelColumn(p.X);
<span style="color: blue;">int</span> row = raster.ToPixelRow(p.Y);
<span style="color: green;">//Get the value at first band.</span>
<span style="color: blue;">object</span> pixelValue = raster.GetPixelValue(0, col, row);
<span style="color: blue;">if</span> (pixelValue != <span style="color: blue;">null</span>)
{
<span style="color: blue;">double</span> pixel = <span style="color: #2b91af;">Convert</span>.ToDouble(pixelValue);
<span style="color: #2b91af;">IFeature</span> featureObserver = featureClassObserver.CreateFeature();
featureObserver.Shape = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(p.X, p.Y, pixel + offset);
idObserver++;
featureObserver.set_Value(idxIdObserver, idObserver);
featureObserver.Store();
isAddObserver = <span style="color: blue;">true</span>;
<span style="color: blue;">continue</span>;
}
}
}
<span style="color: blue;">catch</span>
{
}
}
<span style="color: blue;">if</span> (!isAddObserver)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"Observer not found!"</span>);
}</pre>
<br />
<a href="http://sit2.sistemigis.it/js/skyline/" target="_blank">Qui</a> potete vedere la pagina dimostrativa.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1KVxAe0GUGhYLbXJcDrPh3n2Zokf6KWvP3NjMBZV68qYgH2VmKNfNhIbyssGV9Aanhdz_JVbhOKb63HVALUv8YX3-_g7hjCB9RdqZSA5vFb6PkvemrcIAmndVP1s6gL6wYcKAcVuOuFkh/s1600/skyline3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="390" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1KVxAe0GUGhYLbXJcDrPh3n2Zokf6KWvP3NjMBZV68qYgH2VmKNfNhIbyssGV9Aanhdz_JVbhOKb63HVALUv8YX3-_g7hjCB9RdqZSA5vFb6PkvemrcIAmndVP1s6gL6wYcKAcVuOuFkh/s640/skyline3.png" width="640" /></a></div>
<br />
Ora la palla a voi per crearvi modelli o utilizzare analisi 2D/3D da visualizzare nel viewer.<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-48582236985883878102013-08-31T14:25:00.000+02:002013-09-29T12:02:30.994+02:00Quel gran 'pezzo' della ... multi 'patch'Tra le feature 3D abbiamo oltre ai point, polyline e polygon anche le multipatch. <br />
Una feature multipatch è un oggetto GIS che memorizza una collezione di patch per rappresentare l'oggetto 3D. Le patch memorizzano anche la texture, il colore, la trasparenza e le informazioni geometriche che rappresentano le parti della feature (per essere precisi: se la feature è memorizzata in uno shapefile vengono solo memorizzate le informazioni geometriche mentre utilizzando geodatabase la memorizzazione delle informazioni è completa).<br />
<br />
Tutte le multipatch memorizzano i valori z come parte delle coordinate utilizzate per costruire le patch.<br />
Il tipo di geometria multipatch fu inizialmente sviluppato per avere geometrie poligonali 3D non vincolate da regole di validità 2D; difatti, per modellare correttamente i rilievi della superficie interna di un poligono 3D, possono essere utilizzate feature multipatch o superfici funzionali come ad esempio la <a href="http://en.wikipedia.org/wiki/Triangulated_irregular_network" target="_blank">TIN</a>.<br />
<br />
Esempi di feature multipatch: edifici con texture, pali, alberi, formazioni geologiche presenti nel sottosuolo, strutture interrate ecc.<br />
<br />
Per creare una nuova feature class multipatch selezioniamo dal menu <strong>Type </strong><em>Multipatch Features </em>quando definiamo la geometria della feature class mentre per creare feature multipatch possiamo importare modelli esistenti 3D utilizzando gli strumenti di geoprocessing di ArcGIS. Lo strumento<a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q900000083000000.htm" target="_blank"> Layer3D To Feature Class</a> esporta layer con proprietà 3D definite in multipatch feature class mentre lo strumento <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//00q900000097000000" target="_blank">Import 3D Files</a> importa modelli 3D (3D Studio Max, VRML, GeoVRML 2.0, SketchUP 6.0, OpenFlight 15.8, COLLADA e billboard (png, jpeg,bmp,tiff,gif ecc.)) in feature class multipatch.<br />
<br />
Ma ovviamente le feature multipatch possono essere create utilizzando gli arcobjects ed in questo post vediamo nel dettaglio come fare.<br />
<br />
Una multipatch può essere vista come un contenitore di geometrie che rappresenta superfici 3D.<br />
Le geometrie possono essere triangle, triangle fan, triangle strip o gruppi di ring ed una singola multipatch può includere una o più di queste geometrie.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhImS6AMW9_2pXX2iR2yvQ9xh3Rfj6RiFfKDEcks9nikKjvlVor4v5ejg00jVMwEM3qWxvi_jjm31rOWQi4vIO3H5xP-LgEw8cAm8zSNcqPx-dHFetSO55-prUQC-e6bdRKhJ86kVRxf3HL/s1600/mp1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhImS6AMW9_2pXX2iR2yvQ9xh3Rfj6RiFfKDEcks9nikKjvlVor4v5ejg00jVMwEM3qWxvi_jjm31rOWQi4vIO3H5xP-LgEw8cAm8zSNcqPx-dHFetSO55-prUQC-e6bdRKhJ86kVRxf3HL/s400/mp1.png" width="400" /></a></div>
<br />
I singoli triangle strip, triangle fan o triangle determinano la superficie stessa mentre uno o più ring possono determinare la superficie da rappresentare.<br />
<br />
In questa immagine è rappresentato un triangle strip con 7 punti:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQz5oVkwweh5YUmXMOqOQCd5s4iLnTdzjFGX2k0IHHVTwHim6m1FTWl0b-pUbDMa3v5Zc__BMYJHGCeF-mjmSmuenUna2b7gro8pMF6K44fZpGei7UHcsZisYq5LmhXndTyhR3x87aLXo7/s1600/mp2.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQz5oVkwweh5YUmXMOqOQCd5s4iLnTdzjFGX2k0IHHVTwHim6m1FTWl0b-pUbDMa3v5Zc__BMYJHGCeF-mjmSmuenUna2b7gro8pMF6K44fZpGei7UHcsZisYq5LmhXndTyhR3x87aLXo7/s640/mp2.gif" width="640" /></a></div>
Per generare un triangle strip aggiungeremo i punti 0,1,2,3,4..6 nella IPointCollection cosicché ogni triangle è creato dal precedente. A esempio il secondo triangle utilizza i punti 1 e 2 del primo triangle.<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: #2b91af;"> IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: #2b91af;">IPointCollection</span> trianglesPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">TriangleStripClass</span>();
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-1, -1, 5), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(4, 2, 8), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(6, 9, 6), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(8, 12, 4), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(13, 14, 5), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(12, 18, 8), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(15, 11, 6), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
multiPatchGeometryCollection.AddGeometry(trianglesPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: blue;">return</span> multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
<br />
Il triangle fan è una sequenza di triangle connessi dove ognuno utilizza il primo punto aggiunto alla collection; pertanto la sequenza dei punti sarà 0,1,2,0,3,0,4 ...,0,n<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcy5NiVQ7rZRsgdTIsAl971vDXwbPa5PA-auf4N_E6ukDiVy9Ij5ASVpwXa4eu6LpnZSNqsnutojg94N8t1LJXF2ReVYpgaIwT3Jf9KEt8xoS_LYVqxrJiuB1faWwZgqY8MpkH2qxsa2EA/s1600/mp3.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcy5NiVQ7rZRsgdTIsAl971vDXwbPa5PA-auf4N_E6ukDiVy9Ij5ASVpwXa4eu6LpnZSNqsnutojg94N8t1LJXF2ReVYpgaIwT3Jf9KEt8xoS_LYVqxrJiuB1faWwZgqY8MpkH2qxsa2EA/s320/mp3.gif" width="320" /></a></div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: #2b91af;"> IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: #2b91af;">IPointCollection</span> triangleFanPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">TriangleFanClass</span>();
triangleFanPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 0, 7), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
triangleFanPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-6, -6, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
triangleFanPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-6, 6, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
triangleFanPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(6, 6, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
triangleFanPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(6, -6, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
triangleFanPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-6, -6, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
multiPatchGeometryCollection.AddGeometry(triangleFanPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: blue;">return</span> multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
Il triangle è una collezione di triangle dove ogni tripletta di vertici definisce un nuovo triangle; pertanto il numero di vertici da aggiungere alla collection deve essere un multiplo di tre. Questo tipo di patch fu introdotto per gestire oggetti 3D con triangle non connessi.<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: green;"> //Triangles: Six Triangles Lying In Different Planes</span>
<span style="color: #2b91af;">IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: #2b91af;">IPointCollection</span> trianglesPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">TrianglesClass</span>();
<span style="color: green;">//Triangle 1</span>
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(7.5, 7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(10, 7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(7.5, 5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: green;">//Triangle 2</span>
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-7.5, 7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-5, 7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-7.5, 5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: green;">//Triangle 3</span>
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, -5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(2.5, -5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, -7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: green;">//Triangle 4</span>
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 7.5, 2.5), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(2.5, 7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: green;">//Triangle 5</span>
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-7.5, -7.5, 2.5), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-5, -7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-7.5, -7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: green;">//Triangle 6</span>
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(7.5, -7.5, 2.5), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(10, -7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
trianglesPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(7.5, -7.5, 0), <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
multiPatchGeometryCollection.AddGeometry(trianglesPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> missing, <span style="color: blue;">ref</span> missing);
<span style="color: blue;">return</span> multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
La collezione di triangle può anche essere utilizzata per definire un solido chiuso.<br />
<br />
I ring sono elementi geometrici poligonali definiti da una sequenza di segmenti connessi chiusa.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheOnduZZC0j-9VwAPZJOh6tFYHsiSvTJrcPVJbjYtM-6O5U0SRvWaeYCajKW_TVODYyLl1zlHv-NoIXJ30nr7Ny1k_Lye_190w24wODfGmePF2dVwJcdvJh7vgohrvxPr2lKHS9-jz3yWs/s1600/mp6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheOnduZZC0j-9VwAPZJOh6tFYHsiSvTJrcPVJbjYtM-6O5U0SRvWaeYCajKW_TVODYyLl1zlHv-NoIXJ30nr7Ny1k_Lye_190w24wODfGmePF2dVwJcdvJh7vgohrvxPr2lKHS9-jz3yWs/s400/mp6.png" width="400" /></a></div>
<br />
<br />
Tutti i ring hanno la stessa struttura ma ognuno ha un ruolo ben definito quando definiamo la superficie multipatch. Il ruolo di ogni ring è determinato dal multipatch che lo contiene e non dal ring stesso.<br />
I ruoli sono: Ring (unknown), First Ring, Inner Ring, Outer Ring. Una regola che non è forzata ma che dovrebbe essere seguita quando si crea un gruppo ring è che tutti i ring in un gruppo devono essere <a href="http://it.wikipedia.org/wiki/Complanarit%C3%A0" target="_blank">complanari.</a> Questo è uno standard OpenGL per grafica 3D.<br />
<br />
Pertanto, se dovessimo creare un cubo, dovrà essere composto da 6 superfici rappresentate con un ring o possiamo in alternativa creare una singola superficie utilizzando un triangle strip.<br />
<br />
Una sequenza di ring può descrivere una superficie poligonale con 'buchi'. La sequenza tipicamente consiste di un outer ring, che rappresenta il contorno della patch seguita da un numero di inner ring che rappresentano i 'buchi'. <br />
<br />
Il First Ring determina l'inizio di un gruppo di ring che viene interrotta con un tipo diverso da Ring.<br />
<br />
Quando i tipi di ring sono sconosciuti e rappresentano una patch poligonale con 'buchi' la sequenza deve partire con un First Ring seguito dai ring. Se una sequenza di Ring non è preceduta da un First Ring è trattata come una sequenza di outer ring senza 'buchi'.<br />
<br />
L'ordine delle parti è significativo: gli inner ring devono seguire i loro outer ring; una sequenza di ring che rappresenta una singola superficie patch deve iniziare con un ring del tipo First ring.<br />
<br />
Un'altra regola è che c'è un solo gruppo per outer ring. Se, ad esempio, c'è un altro ring complanare all'interno di un 'buco', questo dovrebbe essere rappresentato da un altro gruppo. Questo perché è effettivamente un'altra superficie anche se è complanare con l'outer ring e l'inner ring.<br />
<br />
Con le regole viste, ad esempio, se dovessimo creare una superficie di una feature multipatch composta dalla sequenza di superfici così definite: triangle strip, triangle fan, ring, ring, ring, first ring, ring verranno così interpretate:<br />
1° superficie: triangle strip<br />
2° superficie: traingle fan<br />
3° superficie: ring<br />
4° superficie: ring<br />
5° superficie: first ring, ring<br />
<br />
<br />
Qui vediamo una multipatch composta da una superficie rappresentata con un ring<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMISX8tNyHtI2tGj-ZUnJpFwc4FH32XCUyUHevc-0buOBWEzs1tYax_fxVDVIIl_AVwzq0PpbxaHutuSaOUHWw4rqRngVgfsGzYYeJUwMVhyphenhypheng2DApj-NVex1CDmS0Q5rPTbqx-UoU4uniA/s1600/mp4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMISX8tNyHtI2tGj-ZUnJpFwc4FH32XCUyUHevc-0buOBWEzs1tYax_fxVDVIIl_AVwzq0PpbxaHutuSaOUHWw4rqRngVgfsGzYYeJUwMVhyphenhypheng2DApj-NVex1CDmS0Q5rPTbqx-UoU4uniA/s320/mp4.png" width="320" /></a></div>
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: #2b91af;"> IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: #2b91af;">IPointCollection</span> ringPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
ringPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-7.5, 0, 0), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
ringPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-7.5, 0, 7.5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
ringPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(7.5, 0, 7.5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
ringPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(7.5, 0, 0), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
ringPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-7.5, 0, 0), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatchGeometryCollection.AddGeometry(ringPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: blue;">return</span> multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
<div style="text-align: center;">
Qui vediamo una multipatch composta da una superficie rappresentata con un ring con un 'buco'<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt1JxptegCS7X5oBIcbUBB-ZWZWLXvazC9gEGPk2RezF8tKTxkB5pA6wlqJzwRtjYhIH_arX9EVeLoKVcQUhYwmvu37zEjKjRgXuxOVW19v5d3qQyeelCrLfRC32Y9vSkC_4K3vO7t1d-f/s1600/mp5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt1JxptegCS7X5oBIcbUBB-ZWZWLXvazC9gEGPk2RezF8tKTxkB5pA6wlqJzwRtjYhIH_arX9EVeLoKVcQUhYwmvu37zEjKjRgXuxOVW19v5d3qQyeelCrLfRC32Y9vSkC_4K3vO7t1d-f/s320/mp5.png" width="320" /></a></div>
<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: #2b91af;"> IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: #2b91af;">IMultiPatch</span> multiPatch = multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IMultiPatch</span>;
<span style="color: green;">//Exterior Ring 1</span>
<span style="color: #2b91af;">IPointCollection</span> exteriorRing1PointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(5, 0, -5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-5, 0, -5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-5, 0, 5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(5, 0, 5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IRing</span> exteriorRing1 = exteriorRing1PointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IRing</span>;
exteriorRing1.Close();
multiPatchGeometryCollection.AddGeometry(exteriorRing1 <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatch.PutRingType(exteriorRing1, <span style="color: #2b91af;">esriMultiPatchRingType</span>.esriMultiPatchOuterRing);
<span style="color: green;">//Interior Ring 1</span>
<span style="color: #2b91af;">IPointCollection</span> interiorRing1PointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-4, 0, -4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(4, 0, -4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(4, 0, 4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-4, 0, 4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IRing</span> interiorRing1 = interiorRing1PointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IRing</span>;
interiorRing1.Close();
multiPatchGeometryCollection.AddGeometry(interiorRing1 <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatch.PutRingType(interiorRing1, <span style="color: #2b91af;">esriMultiPatchRingType</span>.esriMultiPatchInnerRing);
<span style="color: blue;">return</span> multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
Qui vediamo una multipatch con multipli outer ring e multipli inner ring<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0MiPtuNQJrc2J_hGVvOCK26I4XC06FNiOAoRW1JHhtcNUm_C-StXy1MfONfOTifTwxAWK0HgsHYC8vpTdeE0gdgVM3Ucr2DpB7HhBwtgvGHsd7NVQl-i4cWbFFpfrzYdT7220jIYxxEK5/s1600/mp7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0MiPtuNQJrc2J_hGVvOCK26I4XC06FNiOAoRW1JHhtcNUm_C-StXy1MfONfOTifTwxAWK0HgsHYC8vpTdeE0gdgVM3Ucr2DpB7HhBwtgvGHsd7NVQl-i4cWbFFpfrzYdT7220jIYxxEK5/s400/mp7.png" width="400" /></a></div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: green;"> //RingGroup: Upright Square Composed Of Multiple Exterior Rings And Multiple Interior Rings</span>
<span style="color: #2b91af;">IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: #2b91af;">IMultiPatch</span> multiPatch = multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IMultiPatch</span>;
<span style="color: green;">//Exterior Ring 1</span>
<span style="color: #2b91af;">IPointCollection</span> exteriorRing1PointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(5, 0, -5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-5, 0, -5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-5, 0, 5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(5, 0, 5), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IRing</span> exteriorRing1 = exteriorRing1PointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IRing</span>;
exteriorRing1.Close();
multiPatchGeometryCollection.AddGeometry(exteriorRing1 <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatch.PutRingType(exteriorRing1, <span style="color: #2b91af;">esriMultiPatchRingType</span>.esriMultiPatchOuterRing);
<span style="color: green;">//Interior Ring 1</span>
<span style="color: #2b91af;">IPointCollection</span> interiorRing1PointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-4, 0, -4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(4, 0, -4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(4, 0, 4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing1PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-4, 0, 4), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IRing</span> interiorRing1 = interiorRing1PointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IRing</span>;
interiorRing1.Close();
multiPatchGeometryCollection.AddGeometry(interiorRing1 <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatch.PutRingType(interiorRing1, <span style="color: #2b91af;">esriMultiPatchRingType</span>.esriMultiPatchInnerRing);
<span style="color: green;">//Exterior Ring 2 </span>
<span style="color: #2b91af;">IPointCollection</span> exteriorRing2PointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
exteriorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(3, 0, -3), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-3, 0, -3), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-3, 0, 3), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(3, 0, 3), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IRing</span> exteriorRing2 = exteriorRing2PointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IRing</span>;
exteriorRing2.Close();
multiPatchGeometryCollection.AddGeometry(exteriorRing2 <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatch.PutRingType(exteriorRing2, <span style="color: #2b91af;">esriMultiPatchRingType</span>.esriMultiPatchOuterRing);
<span style="color: green;">//Interior Ring 2</span>
<span style="color: #2b91af;">IPointCollection</span> interiorRing2PointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
interiorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-2, 0, -2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(2, 0, -2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(2, 0, 2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
interiorRing2PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-2, 0, 2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IRing</span> interiorRing2 = interiorRing2PointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IRing</span>;
interiorRing2.Close();
multiPatchGeometryCollection.AddGeometry(interiorRing2 <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatch.PutRingType(interiorRing2, <span style="color: #2b91af;">esriMultiPatchRingType</span>.esriMultiPatchInnerRing);
<span style="color: green;">//Exterior Ring 3 </span>
<span style="color: #2b91af;">IPointCollection</span> exteriorRing3PointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">RingClass</span>();
exteriorRing3PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(1, 0, -1), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing3PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-1, 0, -1), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing3PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(-1, 0, 1), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
exteriorRing3PointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(1, 0, 1), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IRing</span> exteriorRing3 = exteriorRing3PointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IRing</span>;
exteriorRing3.Close();
multiPatchGeometryCollection.AddGeometry(exteriorRing3 <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
multiPatch.PutRingType(exteriorRing3, <span style="color: #2b91af;">esriMultiPatchRingType</span>.esriMultiPatchOuterRing);
<span style="color: blue;">return</span> multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<br />
La principale differenza dal punto di vista dello sviluppatore tra il ring ed il triangle è che quando si accede ad un punto del triangle tramite IPointCollection::GetPoint(index) abbiamo un riferimento all'oggetto e quindi possiamo modificarlo direttamente mentre per il ring faremo riferimento ad una copia dell'oggetto e pertanto per modificare un punto dovremo utilizzare IPointCollection::UpdatePoint.<br />
<br />
Un'interfaccia molto utile per la generazione di parti di multipatch dove i vertici sono spaziati ad intervalli fissi è la <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m0000040w000000.htm">IVector3D.</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOq5nL2kdSkEjNXXOO-vVqoqf5iozm1bx5pZwNInXmCqsEgNh8hqzGQ0r7cUoIgoLkmFz_KfNa9sIfigD1Jz9YuTh2UcAKv6Y9_nfjhx5UlBJHpJVyXQa4PdyzRhaNpG9Yk7opB290lHGV/s1600/mp9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="227" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOq5nL2kdSkEjNXXOO-vVqoqf5iozm1bx5pZwNInXmCqsEgNh8hqzGQ0r7cUoIgoLkmFz_KfNa9sIfigD1Jz9YuTh2UcAKv6Y9_nfjhx5UlBJHpJVyXQa4PdyzRhaNpG9Yk7opB290lHGV/s400/mp9.png" width="400" /></a></div>
<br />
<br />
Ad esempio se dovessimo generare un cono <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoGHsAy6h-eULGWXHl-BiSsTOqIQyiYD74T-2Dnm3pGRCcN104igPbaFWJym_H88emzwPW_T6rdsvRjssvsN7BAo6PbNj3xBJe0Kr3NF3QT4CQ4XeJYr22UlYIXlWiuRMTckfIRp_A9WAb/s1600/mp8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="361" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoGHsAy6h-eULGWXHl-BiSsTOqIQyiYD74T-2Dnm3pGRCcN104igPbaFWJym_H88emzwPW_T6rdsvRjssvsN7BAo6PbNj3xBJe0Kr3NF3QT4CQ4XeJYr22UlYIXlWiuRMTckfIRp_A9WAb/s400/mp8.png" width="400" /></a></div>
<br />
<br />
potremmo scrivere il seguente codice:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> const</span> <span style="color: blue;">double</span> ConeBaseDegrees = 360.0;
<span style="color: blue;">const</span> <span style="color: blue;">int</span> ConeBaseDivisions = 36;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> VectorComponentOffset = 0.0000001;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> ConeBaseRadius = 6;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> ConeBaseZ = 0.0;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> ConeApexZ = 9.5;</pre>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
<span style="color: green;">//Vector3D: Cone, TriangleFan With 36 Vertices</span>
<span style="color: #2b91af;">IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: #2b91af;">IPointCollection</span> triangleFanPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">TriangleFanClass</span>();
<span style="color: green;">//Set Cone Apex To (0, 0, ConeApexZ)</span>
<span style="color: #2b91af;">IPoint</span> coneApexPoint = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 0, ConeApexZ);
<span style="color: green;">//Add Cone Apex To Triangle Fan</span>
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
triangleFanPointCollection.AddPoint(coneApexPoint, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: green;">//Define Upper Portion Of Axis Around Which Vector Should Be Rotated To Generate Cone Base Vertices</span>
<span style="color: #2b91af;">IVector3D</span> upperAxisVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 0, 10);
<span style="color: green;">//Define Lower Portion of Axis Around Which Vector Should Be Rotated To Generate Cone Base Vertices</span>
<span style="color: #2b91af;">IVector3D</span> lowerAxisVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 0, -10);
<span style="color: green;">//Add A Slight Offset To X or Y Component Of One Of Axis Vectors So Cross Product Does Not Return A Zero-Length Vector</span>
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
lowerAxisVector3D.XComponent += VectorComponentOffset;
<span style="color: green;">//Obtain Cross Product Of Upper And Lower Axis Vectors To Obtain Normal Vector To Axis Of Rotation To Generate Cone Base Vertices</span>
<span style="color: #2b91af;">IVector3D</span> normalVector3D = upperAxisVector3D.CrossProduct(lowerAxisVector3D) <span style="color: blue;">as</span> <span style="color: #2b91af;">IVector3D</span>;
<span style="color: green;">//Set Normal Vector Magnitude Equal To Radius Of Cone Base</span>
normalVector3D.Magnitude = ConeBaseRadius;
<span style="color: green;">//Obtain Angle Of Rotation In Radians As Function Of Number Of Divisions Within 360 Degree Sweep Of Cone Base</span>
<span style="color: blue;">double</span> rotationAngleInRadians = <span style="color: #2b91af;">GeometryUtilities</span>.GetRadians(ConeBaseDegrees / ConeBaseDivisions);</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < ConeBaseDivisions; i++)
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
{</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
<span style="color: green;">//Rotate Normal Vector Specified Rotation Angle In Radians Around Either Upper Or Lower Axis</span>
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
normalVector3D.Rotate(-1 * rotationAngleInRadians, upperAxisVector3D);
<span style="color: green;">//Construct Cone Base Vertex Whose XY Coordinates Are The Sum Of Apex XY Coordinates And Normal Vector XY Components</span>
<span style="color: #2b91af;">IPoint</span> vertexPoint = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(coneApexPoint.X + normalVector3D.XComponent, coneApexPoint.Y + normalVector3D.YComponent, ConeBaseZ);
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
<span style="color: green;">//Add Vertex To TriangleFan</span>
triangleFanPointCollection.AddPoint(vertexPoint, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
}
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
<span style="color: green;">//Re-Add The Second Point Of The Triangle Fan (First Vertex Added) To Close The Fan</span>
triangleFanPointCollection.AddPoint(triangleFanPointCollection.get_Point(1), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
<span style="color: green;">//Add TriangleFan To MultiPatch</span>
multiPatchGeometryCollection.AddGeometry(triangleFanPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: blue;">return</span> multiPatchGeometryCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</div>
<br />
<br />
In questo esempio per simulare il cono utilizziamo il triangle fan e per generare i vertici della base ruotiamo in senso orario un vettore sul piano XY intorno all'asse delle Z (asse del cono). Al vettore impostiamo la magnitudine uguale al raggio della base.<br />
Prima impostiamo l'apice del cono aggiungendolo alla collection del triangle fan.<br />
Ora definiamo due vettori di magnitudine arbitraria e ne eseguimo il<a href="https://it.wikipedia.org/wiki/Prodotto_vettoriale" target="_blank"> prodotto vettoriale</a> per determinare il vettore perpendicolare ad entrambi e ne impostiamo la magnitudine al valore del raggio della base. Per evitare di avere, nel prodotto vettoriale, un vettore con lunghezza nulla aggiungiamo un piccolo offset alla componente X di uno dei due vettori e impostiamo nel rotate il valore negativo per far ruotare il vettore in senso orario visto che il rotate segue la convenzione matematica e quindi angolo positivo significa senso antiorario.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinox0vCKJRCD1qxLt8-5uv9Zco0rJ4LHPKvgwtWtISIK4k_YUZuGp-LxC_1Urf5JgfDWfO1ef3ouPm3XZLVJf0aW3plE_SVntzgUU4scp4YAWcG4TOKKt8Ysz1Pf8I0SpQnwqrI2BScMV3/s1600/mp10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinox0vCKJRCD1qxLt8-5uv9Zco0rJ4LHPKvgwtWtISIK4k_YUZuGp-LxC_1Urf5JgfDWfO1ef3ouPm3XZLVJf0aW3plE_SVntzgUU4scp4YAWcG4TOKKt8Ysz1Pf8I0SpQnwqrI2BScMV3/s320/mp10.png" width="320" /></a></div>
Ruotando il vettore a x b determiniamo i vertici da aggiungere alla collection. In questo caso abbiamo applicato una definizione con 36 vertici. <br />
Per creare tubi o cilindri possiamo utilizzare la stessa tecnica ma in questo caso utilizzeremo un triangle strip aggiungendo alternativamente alla collezione i vertici creati con la rotazione dei vettori delle relative due basi circolari.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Dt32l6piswVybcQ8bL1b2OYUCK-lpidvGExEq5c3yUxrMkPCqCeA4j3a0DuI7J9yXpoS6XZhrNegL9GwCVdSYI7tPK-Z8PXCnWR_fYs4MaY-Y6ks_X5Xx7m7W0IlPjyn66_-u96K7nKi/s1600/mp11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="327" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Dt32l6piswVybcQ8bL1b2OYUCK-lpidvGExEq5c3yUxrMkPCqCeA4j3a0DuI7J9yXpoS6XZhrNegL9GwCVdSYI7tPK-Z8PXCnWR_fYs4MaY-Y6ks_X5Xx7m7W0IlPjyn66_-u96K7nKi/s400/mp11.png" width="400" /></a></div>
<br />
Un'altra interfaccia utile è l'<a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m000003w9000000.htm" target="_blank">ITransform3D</a> che ti consente di spostare, scalare o ruotare intorno ad un asse una geometria esistente.<br />
L'interfaccia è utile perché possiamo generare la nostra geometria in un frame di riferimento (ad esempio centrata sullo 0,0,0) e poi trasformarla per posizionarla nella posizione corretta.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzhLg1clzRJHWxEz3OoGx4L-TJTArheA9RFYT3PtWICrZzgzFOzj-d5v58QeZigtXjvBp9EWqIfRvxTvWWGFO4lOev3rybZ_rcVmlN-nC8VqGY12FYXoeyzTbA8mmU_iziPqX-1zE1yG-R/s1600/mp13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="309" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzhLg1clzRJHWxEz3OoGx4L-TJTArheA9RFYT3PtWICrZzgzFOzj-d5v58QeZigtXjvBp9EWqIfRvxTvWWGFO4lOev3rybZ_rcVmlN-nC8VqGY12FYXoeyzTbA8mmU_iziPqX-1zE1yG-R/s320/mp13.png" width="320" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMrTc0v3qDClCq22eUBe-puRKYQPgRWCDpnrrhsCIqgn9EGHLROVnK92AYsTxVnSAgru850bTFDl57P8l36KUuF2erLX3WwnJPU8NCpsJ3EBHDeakPogDKOMek828KK3N_jsez7yVP4Bn9/s1600/mp12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMrTc0v3qDClCq22eUBe-puRKYQPgRWCDpnrrhsCIqgn9EGHLROVnK92AYsTxVnSAgru850bTFDl57P8l36KUuF2erLX3WwnJPU8NCpsJ3EBHDeakPogDKOMek828KK3N_jsez7yVP4Bn9/s400/mp12.png" width="393" /></a></div>
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> const</span> <span style="color: blue;">double</span> XScale = 0.5;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> YScale = 0.5;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> ZScale = 2;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> XOffset = -5;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> YOffset = -5;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> ZOffset = -8;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> DegreesOfRotation = 90;
<span style="color: green;">//Transform3D: Cylinder Scaled, Rotated, Repositioned Via Move3D(), Scale3D(), RotateVector3D()</span>
<span style="color: #2b91af;">IGeometry</span> geometry = <span style="color: #2b91af;"></span>GetCylinder();
<span style="color: #2b91af;">ITransform3D</span> transform3D = geometry <span style="color: blue;">as</span> <span style="color: #2b91af;">ITransform3D</span>;
<span style="color: green;">//Stretch The Cylinder So It Looks Like A Tube</span>
<span style="color: #2b91af;">IPoint</span> originPoint = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 0, 0);
transform3D.Scale3D(originPoint, XScale, YScale, ZScale);
<span style="color: green;">//Rotate The Cylinder So It Lies On Its Side</span>
<span style="color: #2b91af;">IVector3D</span> axisOfRotationVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 10, 0);
<span style="color: blue;">double</span> angleOfRotationInRadians = <span style="color: #2b91af;">GeometryUtilities</span>.GetRadians(DegreesOfRotation);
transform3D.RotateVector3D(axisOfRotationVector3D, angleOfRotationInRadians);
<span style="color: green;">//Reposition The Cylinder So It Is Located Underground</span>
transform3D.Move3D(XOffset, YOffset, ZOffset);
<span style="color: blue;">return</span> geometry;</pre>
<br />
In questo esempio con multiple chiamate ai metodi esposti dal <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/index.html#//002m000003w9000000" target="_blank">ITransform3D</a> scaliamo, ruotiamo e spostiamo il cilindro che vediamo nella prima immagine.<br />
<br />
L'interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m000000vp000000.htm" target="_blank">IConstructMultiPatch</a> ci consente di estrudere una base 2D o 3D in diversi modi per generare la rappresentazione multipatch.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwLjWegOzFmJ4Pdz-66QCq7KhfFzNNNTloFhts_CA7AjuZfqIUoBD2EU6Hh8UQdet3J_2QCcwcZmABUg19I9HhjunLqNIy8tYRz5QHeUYF3JQqKWO111twb1G2do6pJYUHhAo1QGYVllbL/s1600/mp14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwLjWegOzFmJ4Pdz-66QCq7KhfFzNNNTloFhts_CA7AjuZfqIUoBD2EU6Hh8UQdet3J_2QCcwcZmABUg19I9HhjunLqNIy8tYRz5QHeUYF3JQqKWO111twb1G2do6pJYUHhAo1QGYVllbL/s400/mp14.png" width="381" /></a></div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> const</span> <span style="color: blue;">double</span> FromZ = 0;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> ToZ = 9.5;
<span style="color: green;">//Extrusion: Square Shaped 2D Polygon Extruded To Generate 3D Building Via ConstructExtrudeFromTo()</span>
<span style="color: #2b91af;">IPointCollection</span> polygonPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">PolygonClass</span>();
polygonPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(-2, 2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
polygonPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(2, 2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
polygonPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(2, -2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
polygonPointCollection.AddPoint(<span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(-2, -2), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: #2b91af;">IPolygon</span> polygon = polygonPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IPolygon</span>;
polygon.Close();
<span style="color: #2b91af;">IGeometry</span> polygonGeometry = polygonPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;
<span style="color: #2b91af;">ITopologicalOperator</span> topologicalOperator = polygonGeometry <span style="color: blue;">as</span> <span style="color: #2b91af;">ITopologicalOperator</span>;
topologicalOperator.Simplify();
<span style="color: #2b91af;">IConstructMultiPatch</span> constructMultiPatch = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
constructMultiPatch.ConstructExtrudeFromTo(FromZ, ToZ, polygonGeometry);
<span style="color: blue;">return</span> constructMultiPatch <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
In questo esempio abbiamo generato un poligono sul piano xy visto che è generato da sole coordinate x,y (no z-aware). Verifichiamo che il poligono sia topologicamente corretto ed effettuiamo l'estrusione tra due altezze conosciute. In questo caso la multipatch generata sarà composta da due ring (uno in alto ed uno in basso) e da un triangle strip rappresentanti le facce laterali del prisma retto.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiycAmrnCPqbqhIvpl7PcgQ_w6drwWWlWej4I5BL0LhGHSkvDBI_lQeoiDOBRLTASJcnFVn0949EVtyQSs0ox8NTXh5jXaSuV0w3Oayp6ljwOHqbsEQf-PzgaqCzpVRyjz7BTU9SHS-rv8Q/s1600/mp15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiycAmrnCPqbqhIvpl7PcgQ_w6drwWWlWej4I5BL0LhGHSkvDBI_lQeoiDOBRLTASJcnFVn0949EVtyQSs0ox8NTXh5jXaSuV0w3Oayp6ljwOHqbsEQf-PzgaqCzpVRyjz7BTU9SHS-rv8Q/s400/mp15.png" width="400" /></a></div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> const</span> <span style="color: blue;">double</span> CircleDegrees = 360.0;
<span style="color: blue;">const</span> <span style="color: blue;">int</span> CircleDivisions = 36;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> VectorComponentOffset = 0.0000001;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> CircleRadius = 3.0;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> BaseZ = 0.0;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> RotationAngleInDegrees = 89.9;
<span style="color: green;">//Extrusion: 3D Circle Polyline Extruded Along 3D Vector Via ConstructExtrudeRelative()</span>
<span style="color: #2b91af;">IPointCollection</span> pathPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">PathClass</span>();
<span style="color: #2b91af;">IGeometry</span> pathGeometry = pathPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;
<span style="color: #2b91af;">GeometryUtilities</span>.MakeZAware(pathGeometry);
<span style="color: #2b91af;">IPoint</span> originPoint = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 0, 0);
<span style="color: #2b91af;">IVector3D</span> upperAxisVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 0, 10);
<span style="color: #2b91af;">IVector3D</span> lowerAxisVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 0, -10);
lowerAxisVector3D.XComponent += VectorComponentOffset;
<span style="color: #2b91af;">IVector3D</span> normalVector3D = upperAxisVector3D.CrossProduct(lowerAxisVector3D) <span style="color: blue;">as</span> <span style="color: #2b91af;">IVector3D</span>;
normalVector3D.Magnitude = CircleRadius;
<span style="color: blue;">double</span> rotationAngleInRadians = <span style="color: #2b91af;">GeometryUtilities</span>.GetRadians(CircleDegrees / CircleDivisions);
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < CircleDivisions; i++)
{
normalVector3D.Rotate(-1 * rotationAngleInRadians, upperAxisVector3D);
<span style="color: #2b91af;">IPoint</span> vertexPoint = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(originPoint.X + normalVector3D.XComponent,
originPoint.Y + normalVector3D.YComponent,
BaseZ);
pathPointCollection.AddPoint(vertexPoint, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
}
pathPointCollection.AddPoint(pathPointCollection.get_Point(0), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
<span style="color: green;">//Rotate Geometry</span>
<span style="color: #2b91af;">IVector3D</span> rotationAxisVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 10, 0);
<span style="color: #2b91af;">ITransform3D</span> transform3D = pathGeometry <span style="color: blue;">as</span> <span style="color: #2b91af;">ITransform3D</span>;
transform3D.RotateVector3D(rotationAxisVector3D, <span style="color: #2b91af;">GeometryUtilities</span>.GetRadians(RotationAngleInDegrees));
<span style="color: green;">//Construct Polyline From Path Vertices</span>
<span style="color: #2b91af;">IGeometry</span> polylineGeometry = <span style="color: blue;">new</span> <span style="color: #2b91af;">PolylineClass</span>();
<span style="color: #2b91af;">GeometryUtilities</span>.MakeZAware(polylineGeometry);
<span style="color: #2b91af;">IPointCollection</span> polylinePointCollection = polylineGeometry <span style="color: blue;">as</span> <span style="color: #2b91af;">IPointCollection</span>;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < pathPointCollection.PointCount; i++)
{
polylinePointCollection.AddPoint(pathPointCollection.get_Point(i), <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
}
<span style="color: #2b91af;">ITopologicalOperator</span> topologicalOperator = polylineGeometry <span style="color: blue;">as</span> <span style="color: #2b91af;">ITopologicalOperator</span>;
topologicalOperator.Simplify();
<span style="color: green;">//Define Vector To Extrude Along</span>
<span style="color: #2b91af;">IVector3D</span> extrusionVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(10, 0, 5);
<span style="color: green;">//Perform Extrusion</span>
<span style="color: #2b91af;">IConstructMultiPatch</span> constructMultiPatch = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
constructMultiPatch.ConstructExtrudeRelative(extrusionVector3D, polylineGeometry);
<span style="color: blue;">return</span> constructMultiPatch <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
In questo caso utilizziamo il ConstructExtrudeRelative() definendo un poligono che rappresenta un cerchio, lo ruotiamo di circa 90 gradi e poi lo estrudiamo lungo un dato vettore generando la multipatch.<br />
<br />
Se abbiamo superfici funzionali possiamo anche, utilizzando come base un poligono o una polilinea, generare una multipatch tra queste due surperfici.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDpcZ9eE0BPi1G1wc438bohnqHlbd-Nuuf32bsXlU7lfF6V-hPRVd0iAEsqEl51E56fefHEAlyJW40mZGCbhUye3Qhb0lLaXETo7qD7okGi5zrG4le0fJA5xMl6Vk6M5eu0Nfwnco4n35J/s1600/mp16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDpcZ9eE0BPi1G1wc438bohnqHlbd-Nuuf32bsXlU7lfF6V-hPRVd0iAEsqEl51E56fefHEAlyJW40mZGCbhUye3Qhb0lLaXETo7qD7okGi5zrG4le0fJA5xMl6Vk6M5eu0Nfwnco4n35J/s640/mp16.png" width="640" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1DjWvSjjGhlMtUdanwZd0xzhRfJsPOtrJc014jjHAiX34WNByAFlbRSrXbfTP21vsfYtNIW949YvjjYAwq5CT-wjHOHRJnnCkNK-V9ysqSJaWnq-3O4lvhOysf5bsCGGfy4RmLN3hyphenhyphenZTR/s1600/mp17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1DjWvSjjGhlMtUdanwZd0xzhRfJsPOtrJc014jjHAiX34WNByAFlbRSrXbfTP21vsfYtNIW949YvjjYAwq5CT-wjHOHRJnnCkNK-V9ysqSJaWnq-3O4lvhOysf5bsCGGfy4RmLN3hyphenhyphenZTR/s400/mp17.png" width="400" /></a></div>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> const</span> <span style="color: blue;">double</span> CircleDegrees = 360.0;
<span style="color: blue;">const</span> <span style="color: blue;">int</span> CircleDivisions = 36;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> VectorComponentOffset = 0.0000001;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> CircleRadius = 9.5;
<span style="color: blue;">const</span> <span style="color: blue;">int</span> PointCount = 100;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> UpperZMin = 7;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> UpperZMax = 10;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> LowerZMin = 0;
<span style="color: blue;">const</span> <span style="color: blue;">double</span> LowerZMax = 3;
<span style="color: green;">//Extrusion: Circle Shaped Base Geometry Extruded Between Two Different TIN-Based Functional Surfaces</span>
<span style="color: #2b91af;">IGeometryCollection</span> multiPatchGeometryCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
<span style="color: green;">//Base Geometry</span>
<span style="color: #2b91af;">IPointCollection</span> polygonPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">PolygonClass</span>();
<span style="color: #2b91af;">IPoint</span> originPoint = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 0, 0);
<span style="color: #2b91af;">IVector3D</span> upperAxisVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 0, 10);
<span style="color: #2b91af;">IVector3D</span> lowerAxisVector3D = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructVector3D(0, 0, -10);
lowerAxisVector3D.XComponent += VectorComponentOffset;
<span style="color: #2b91af;">IVector3D</span> normalVector3D = upperAxisVector3D.CrossProduct(lowerAxisVector3D) <span style="color: blue;">as</span> <span style="color: #2b91af;">IVector3D</span>;
normalVector3D.Magnitude = CircleRadius;
<span style="color: blue;">double</span> rotationAngleInRadians = <span style="color: #2b91af;">GeometryUtilities</span>.GetRadians(CircleDegrees / CircleDivisions);
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < CircleDivisions; i++)
{
normalVector3D.Rotate(-1 * rotationAngleInRadians, upperAxisVector3D);
<span style="color: #2b91af;">IPoint</span> vertexPoint = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(originPoint.X + normalVector3D.XComponent,
originPoint.Y + normalVector3D.YComponent);
polygonPointCollection.AddPoint(vertexPoint, <span style="color: blue;">ref</span> _missing, <span style="color: blue;">ref</span> _missing);
}
<span style="color: #2b91af;">IPolygon</span> polygon = polygonPointCollection <span style="color: blue;">as</span> <span style="color: #2b91af;">IPolygon</span>;
polygon.Close();
<span style="color: #2b91af;">IGeometry</span> baseGeometry = polygon <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;
<span style="color: #2b91af;">ITopologicalOperator</span> topologicalOperator = polygon <span style="color: blue;">as</span> <span style="color: #2b91af;">ITopologicalOperator</span>;
topologicalOperator.Simplify();
<span style="color: green;">//Functional Surfaces</span>
<span style="color: #2b91af;">IEnvelope</span> envelope = <span style="color: blue;">new</span> <span style="color: #2b91af;">EnvelopeClass</span>();
envelope.XMin = -10;
envelope.XMax = 10;
envelope.YMin = -10;
envelope.YMax = 10;
<span style="color: #2b91af;">Random</span> random = <span style="color: blue;">new</span> <span style="color: #2b91af;">Random</span>();
<span style="color: green;">//Upper Functional Surface</span>
<span style="color: #2b91af;">ITinEdit</span> upperTinEdit = <span style="color: blue;">new</span> <span style="color: #2b91af;">TinClass</span>();
upperTinEdit.InitNew(envelope);
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < PointCount; i++)
{
<span style="color: blue;">double</span> x = envelope.XMin + (envelope.XMax - envelope.XMin) * random.NextDouble();
<span style="color: blue;">double</span> y = envelope.YMin + (envelope.YMax - envelope.YMin) * random.NextDouble();
<span style="color: blue;">double</span> z = UpperZMin + (UpperZMax - UpperZMin) * random.NextDouble();
<span style="color: #2b91af;">IPoint</span> point = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(x, y, z);
upperTinEdit.AddPointZ(point, 0);
}
<span style="color: #2b91af;">IFunctionalSurface</span> upperFunctionalSurface = upperTinEdit <span style="color: blue;">as</span> <span style="color: #2b91af;">IFunctionalSurface</span>;
<span style="color: green;">//Lower Functional Surface</span>
<span style="color: #2b91af;">ITinEdit</span> lowerTinEdit = <span style="color: blue;">new</span> <span style="color: #2b91af;">TinClass</span>();
lowerTinEdit.InitNew(envelope);
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < PointCount; i++)
{
<span style="color: blue;">double</span> x = envelope.XMin + (envelope.XMax - envelope.XMin) * random.NextDouble();
<span style="color: blue;">double</span> y = envelope.YMin + (envelope.YMax - envelope.YMin) * random.NextDouble();
<span style="color: blue;">double</span> z = LowerZMin + (LowerZMax - LowerZMin) * random.NextDouble();
<span style="color: #2b91af;">IPoint</span> point = <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(x, y, z);
lowerTinEdit.AddPointZ(point, 0);
}
<span style="color: #2b91af;">IFunctionalSurface</span> lowerFunctionalSurface = lowerTinEdit <span style="color: blue;">as</span> <span style="color: #2b91af;">IFunctionalSurface</span>;
<span style="color: #2b91af;">IConstructMultiPatch</span> constructMultiPatch = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultiPatchClass</span>();
constructMultiPatch.ConstructExtrudeBetween(upperFunctionalSurface, lowerFunctionalSurface, baseGeometry);
<span style="color: blue;">return</span> constructMultiPatch <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;</pre>
<br />
<br />
Come avevamo accennato all'inizio possiamo anche generare multipatch con impostato colore, texture, trasparenza, priorità patch, normale e coordinate della texture, tutte informazioni memorizzate con la geometria. In questo caso per generare la multipatch utilizzeremo <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0009/0009000000n3000000.htm" target="_blank">IGeneralMultipatchCreator</a>.<br />
<br />
Una volta generata la geometria possiamo utilizzarla come simbolo marker 3D per renderizzare un elemento grafico, o salvarlo come template in uno stile o può essere memorizzato in una feature class multipatch.<br />
<br />
<br />
Vediamo un semplicissimo esempio:<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: #2b91af;"> IGeometryMaterial</span> chiusinoGeometryMaterial = <span style="color: blue;">new</span> <span style="color: #2b91af;">GeometryMaterialClass</span>();
chiusinoGeometryMaterial.TextureImage = <span style="color: #a31515;">@"C:\Temp\Multipatch\Data\Images\ChiusinoQuadrato.png"</span>;
<span style="color: #2b91af;">IRgbColor</span> color = <span style="color: blue;">new</span> <span style="color: #2b91af;">RgbColorClass</span>();
color.Red = 255;
color.Green = 255;
color.Blue = 255;
chiusinoGeometryMaterial.TransparentTextureColor = color;
<span style="color: #2b91af;">IGeometryMaterialList</span> geometryMaterialList = <span style="color: blue;">new</span> <span style="color: #2b91af;">GeometryMaterialListClass</span>();
geometryMaterialList.AddMaterial(chiusinoGeometryMaterial);
<span style="color: #2b91af;">IGeneralMultiPatchCreator</span> generalMultiPatchCreator = <span style="color: blue;">new</span> <span style="color: #2b91af;">GeneralMultiPatchCreatorClass</span>();
generalMultiPatchCreator.Init(5, 1, <span style="color: blue;">false</span>, <span style="color: blue;">false</span>, <span style="color: blue;">false</span>, 5, geometryMaterialList);
generalMultiPatchCreator.SetPatchType(0, <span style="color: #2b91af;">esriPatchType</span>.esriPatchTypeOuterRing);
generalMultiPatchCreator.SetPatchPriority(0, 0);
generalMultiPatchCreator.SetMaterialIndex(0, 0);
generalMultiPatchCreator.SetPatchPointIndex(0, 0);
generalMultiPatchCreator.SetPatchTexturePointIndex(0, 0);
generalMultiPatchCreator.SetPoint(0, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 0, height));
generalMultiPatchCreator.SetPoint(1, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, yDimension, height));
generalMultiPatchCreator.SetPoint(2, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(xDimension, yDimension, height));
generalMultiPatchCreator.SetPoint(3, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(xDimension, 0, height));
generalMultiPatchCreator.SetPoint(4, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint3D(0, 0, height));
generalMultiPatchCreator.SetTexturePoint(0, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(0, 0));
generalMultiPatchCreator.SetTexturePoint(1, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(0, 1));
generalMultiPatchCreator.SetTexturePoint(2, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(1, 1));
generalMultiPatchCreator.SetTexturePoint(3, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(1, 0));
generalMultiPatchCreator.SetTexturePoint(4, <span style="color: #2b91af;">GeometryUtilities</span>.ConstructPoint2D(0, 0));
return generalMultiPatchCreator.CreateMultiPatch();</pre>
<br />
Innanzitutto creiamo la lista delle texture che desideriamo aggiungere alla multipatch (in questo esempio 1 sola). Per la texture aggiunta impostiamo anche quale colore dovrà essere trasparente (in questo caso il bianco dell'immagine). Potevamo anche impostare la trasparenza dell'immagine ed un colore utilizzato per renderizzare il materiale (utilizzato come efficiente alternativa alla texture quando occorre renderizzare molte multipatch visualizzate a distanza). Il primo parametro del metodo <strong>Init </strong>rappresenta il numero globale di punti delle geometrie che compongono la multipatch; in questo caso è un poligono con quattro vertici quindi 5 perchè il primo si conta due volte per chiudere il poligono.<br />
Il secondo parametro è il numero di patch che in questo caso è 1 perché abbiamo solo un ring. I tre parametri successivi indicano se si vuole avere a disposizione la M, l'ID e la normale per i vertici della multipatch: ad esempio per un ring che rappresenta un quadrato il primo vertice avrà come M = 0.0, il secondo M=0.25 fino ad arrivare all'ultimo con 1.0 mentre come ID avranno l'indice o l'offset di ciascun punto all'interno della patch.<br />
Infine passiamo il numero di vertici della texture: in questo caso è 5 perchè desiderimo coprire con la texture tutta l'area del poligono e poi la lista della texture.<br />
Impostiamo il tipo di patch: in questo caso solo una - la prima - e quindi passiamo indice 0.<br />
Impostiamo la priorità anche se abbiamo una sola patch e quindi non abbiamo sovrapposizioni. La patch priority può essere utilizzata quando desideriamo specificare l'ordine nella quale le patch devono essere renderizzate, utile quando si hanno sovrapposizioni. Un numero più alto rappresenta priorità più alta.<br />
Impostiamo con <strong>SetMaterialIndex</strong> l'indice della texture della lista dei materiali al quale fa riferimento la patch e con <strong>SetPatchPointIndex</strong> e <strong>SetPatchTexturePointIndex</strong>, gli indici iniziali o offset per la geometria e la texture per relazione tra di loro ogni patch.<br />
Infine impostiamo per ogni singolo vertice la geometria e il relativo 'vertice' per la texture. In questo ultimo caso il valore 1 indica che l'immagine è allungata per riempire la dimensione lungo le due direzioni (0,0) - (1,1). Se avessimo scritto nel range tra (0,0) - (10,3) l'immagine sarebbe ripetuta 10 volte lungo la x e 3 volte lungo la y.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLCjlMRjjzsM_9vUKQsPzMl9jTqioais4OlsOMC5BN0bUmOvwQqEnKigFo2QpE6kGR1IOd4Iz3LeRKoRbgm4-wXlBjt_tmWSihWMrJ4OPOC_4Z42Oi1aL0h9hEt4V3jqrHKrZQ771rpdg2/s1600/mp18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="537" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLCjlMRjjzsM_9vUKQsPzMl9jTqioais4OlsOMC5BN0bUmOvwQqEnKigFo2QpE6kGR1IOd4Iz3LeRKoRbgm4-wXlBjt_tmWSihWMrJ4OPOC_4Z42Oi1aL0h9hEt4V3jqrHKrZQ771rpdg2/s640/mp18.png" width="640" /></a></div>
<br />
Tra le interfacce implementate dalle multipatch abbiamo <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00043nqt000000.htm" target="_blank">IRelationOperator3D2</a> con i metodi <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00000337000000.htm" target="_blank">Disjoint3D</a> e <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00000336000000.htm" target="_blank">IsNear3D</a> che permettono rispettivamente di determinare se due geometrie non hanno punti in comune e se una geometria è entro una certa distanza da un'altra geometria.<br />
Esempio disjoint:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7eWyT8vVEWJ-xMvKah9dk_sE2AWJQPrxbLFT2MGJJgzNiJnch8JqauAAo8L9qvtXX8rrwlQF26UxetCGg8lJjrfw6PMj_OxrD8wB0WEqlS8TVtE0hgOXZJ2RTGk3WF547c2dTwbTnAi1k/s1600/Disjoint3D.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="343" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7eWyT8vVEWJ-xMvKah9dk_sE2AWJQPrxbLFT2MGJJgzNiJnch8JqauAAo8L9qvtXX8rrwlQF26UxetCGg8lJjrfw6PMj_OxrD8wB0WEqlS8TVtE0hgOXZJ2RTGk3WF547c2dTwbTnAi1k/s400/Disjoint3D.gif" width="400" /></a></div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> TestIntersection()
{
<span style="color: #2b91af;">IGeometry</span> polylineGeometry = GetPolylineGeometry();
<span style="color: #2b91af;">IGeometry</span> polygonGeometry = GetPolygonGeometry();
<span style="color: #2b91af;">IRelationalOperator3D</span> relationalOperator3D = polylineGeometry <span style="color: blue;">as</span> <span style="color: #2b91af;">IRelationalOperator3D</span>;
<span style="color: blue;">bool</span> intersect = !(relationalOperator3D.Disjoint3D(polygonGeometry));
<span style="color: green;">//intersect = true</span>
}</pre>
<br />
<br />
<a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00043ntt000000.htm" target="_blank">IVolume</a> e <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00043n44000000.htm" target="_blank">IArea3D</a> ci permetto di avere il volume chiuso e la superficie delle patch delle multipatch mentre con <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00043nq9000000.htm" target="_blank">IProximityOperator3D</a> possiamo determinare il punto più vicino di una multipatch da un determinato punto o farci restituire la distanza minima 3D con un'altra geometria.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD6_l5GY0l3OIexD4k7x-x-feqYjIEuPeBMZk1fAt5KDFJhhpeFPNqzgCbpKOyRKu1i9nCMqiVVxR61CIfqMoeIb4PUNp-qNZ0l-ERrkcYXFayV10Uy7TTyGfZiMtCqazb5jJ6Mnfn-w-c/s1600/QueryNearestPoint3D.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD6_l5GY0l3OIexD4k7x-x-feqYjIEuPeBMZk1fAt5KDFJhhpeFPNqzgCbpKOyRKu1i9nCMqiVVxR61CIfqMoeIb4PUNp-qNZ0l-ERrkcYXFayV10Uy7TTyGfZiMtCqazb5jJ6Mnfn-w-c/s400/QueryNearestPoint3D.gif" width="400" /></a></div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> QueryNearestPoint3D()
{
<span style="color: #2b91af;">IGeometry</span> pointGeometry = GetPointGeometry();
<span style="color: #2b91af;">IGeometry</span> envelopeGeometry = GetEnvelopeGeometry();
<span style="color: #2b91af;">IProximityOperator3D</span> proximityOperator3D = envelopeGeometry <span style="color: blue;">as</span> <span style="color: #2b91af;">IProximityOperator3D</span>;
<span style="color: #2b91af;">IPoint</span> nearestPoint3D = <span style="color: blue;">new</span> <span style="color: #2b91af;">PointClass</span>();
proximityOperator3D.QueryNearestPoint3D(pointGeometry <span style="color: blue;">as</span> <span style="color: #2b91af;">IPoint</span>, <span style="color: #2b91af;">esriSegmentExtension</span>.esriNoExtension, nearestPoint3D);
<span style="color: green;">//nearestPoint3D = (5.393, -0.583, -6.043) </span>
}</pre>
<br />
<br />
<br />
Infine un'interfaccia che ci può essere utile nella costruzione di multipatch è la <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00000327000000.htm" target="_blank">IRay2</a>. <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00000463000000.htm" target="_blank">Ray</a> ha un endpoint (la sua origine) e continua all'infinito nell'altra direzione. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRJ1kk2sCvgSAO0HyF6SX8u-IbWdtVlt8jvBEl4E64P5fc08k_92weiPmslcrcvJ4GncfC710OD2xXvWWXu-rm3v-HLvz7Hda0nppAPn3DXt08kuLN5CeCPDkG-zdFgurKH3UonGQK0WKM/s1600/GeomRay.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRJ1kk2sCvgSAO0HyF6SX8u-IbWdtVlt8jvBEl4E64P5fc08k_92weiPmslcrcvJ4GncfC710OD2xXvWWXu-rm3v-HLvz7Hda0nppAPn3DXt08kuLN5CeCPDkG-zdFgurKH3UonGQK0WKM/s400/GeomRay.gif" width="320" /></a></div>
Per creare un oggetto ray imposteremo la sua origine e un vettore direzionale. L'interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/002m/002m00000327000000.htm" target="_blank">IRay2</a> espone metodi per determinare punti di intersezione tra un oggetto ray e una multipatch.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga6njX-0w3J-AeDyp-NWPnEN5PnVw20HX2076RoX6Sj7Q9mMtHbscOorpcADwbund3iNcSvBwNxoCChM82p20EDOrb9aDsPQJGKusmwxMVB5FWNSbAg0ypDC_ssRmxE7emk2bML-yYf7PG/s1600/IntersectRay.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="337" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga6njX-0w3J-AeDyp-NWPnEN5PnVw20HX2076RoX6Sj7Q9mMtHbscOorpcADwbund3iNcSvBwNxoCChM82p20EDOrb9aDsPQJGKusmwxMVB5FWNSbAg0ypDC_ssRmxE7emk2bML-yYf7PG/s400/IntersectRay.gif" width="400" /></a></div>
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> public</span> <span style="color: blue;">static</span> <span style="color: blue;">void</span> QueryPointsOfIntersection()
{
<span style="color: #2b91af;">ILine</span> line = <span style="color: blue;">new</span> <span style="color: #2b91af;">LineClass</span>();
line.FromPoint = GetPoint();
line.ToPoint = GetPoint();
<span style="color: #2b91af;">IRay</span> ray = <span style="color: blue;">new</span> <span style="color: #2b91af;">RayClass</span>();
ray.Origin = line.FromPoint;
ray.Vector = ConstructVector3D(line.ToPoint.X - line.FromPoint.X, line.ToPoint.Y - line.FromPoint.Y, line.ToPoint.Z - line.FromPoint.Z);
<span style="color: #2b91af;">IGeometry</span> multiPatchGeometry = GetMultiPatchGeometry();
<span style="color: #2b91af;">IPointCollection</span> intersectionPointCollection = <span style="color: blue;">new</span> <span style="color: #2b91af;">MultipointClass</span>();
ray.Intersect(multiPatchGeometry, intersectionPointCollection);
<span style="color: green;">//intersectionPointCollection[0] = (5, -2.13, 0.092)</span>
<span style="color: green;">//intersectionPointCollection[1] = (1.612, -2.651, 7.012)</span>
}</pre>
<br />
<br />
Ora con ArcGIS 10.2 abbiamo anche la possibilità di esportare, tramite il tool <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//00q9000000np000000" target="_blank">Export To 3D Web Scene</a>, i documenti di ArcScene nel formato 3ws (Esri CityEngine Web Scene) che possiamo poi pubblicare e visualizzare con arcgis.com o utilizzando il <a href="http://www.arcgis.com/home/item.html?id=38fede3935a440e49cf316dcae6aae47" target="_blank">web viewer</a> per la visualizzazione dei file 3ws sul proprio server.<br />
Ad esempio potremo crearci delle multipatch al volo tramite una soe arcgis server e visualizzarla con il web viewer<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"> string</span> pathfileNameSxd = System.IO.<span style="color: #2b91af;">Path</span>.Combine(newPath, <span style="color: #a31515;">"Multipatch.sxd"</span>);
System.IO.<span style="color: #2b91af;">File</span>.Copy(System.IO.<span style="color: #2b91af;">Path</span>.Combine(pathRoot, <span style="color: #a31515;">"Multipatch.sxd"</span>), pathfileNameSxd);
<span style="color: #2b91af;">IGeoProcessor2</span> gp = <span style="color: blue;">new</span> <span style="color: #2b91af;">GeoProcessorClass</span>();
<span style="color: #2b91af;">IVariantArray</span> parameters = <span style="color: blue;">new</span> <span style="color: #2b91af;">VarArrayClass</span>();
parameters.Add(pathfileNameSxd);
parameters.Add(System.IO.<span style="color: #2b91af;">Path</span>.Combine(newPath, <span style="color: #a31515;">"Multipatch.3ws"</span>));
gp.Execute(<span style="color: #a31515;">"ExportTo3DWebScene_3d"</span>, parameters, <span style="color: blue;">null</span>);</pre>
<br />
<a href="http://sit2.sistemigis.it/sit/rest/services/alsi/Camerette3D/MapServer/exts/ArcSewer3DSOE/getCameretta3D?oid=4304&f=html" target="_blank">Qui</a> potete vedere un semplice esempio di multipatch create al volo da arcgis server.<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-18462255653270059372013-07-31T11:14:00.000+02:002013-08-07T20:25:10.582+02:00ArcGIS 10.2: cosa chiedere di più?ArcGIS 10.2 è un rilascio completo della piattaforma ArcGIS.<br />
Si tratta, principalmente, di una "quality release", con molte problematiche risolte grazie al programma <em>Esri User Experience Improvement, </em>introdotto con la versione 10.1. <br />
La nuova release comprende funzionalità perfezionate, miglioramenti sulla stabilità, miglior supporto in merito a connettività, sicurezza e nell'utilizzo in ambiente "enterprise".<br />
<br />
ArcGIS 10.2 introduce anche diversi nuovi prodotti. <br />
<em><strong>Portal for ArcGIS</strong></em> può essere ora distribuito sulla propria rete privata per condividere mappe, applicazioni ed altre informazioni geografiche. Un prodotto, quindi, che abilita le capabilities di ArcGIS Online "dietro" il firewall della propria organizzazione. <br />
Utilizzando <em><strong>ArcGIS GeoEvent Processor</strong></em>, nuova extension per ArcGIS for Server, le organizzazioni possono ora processare dati real-time al volo, visualizzando, nei client ArcGIS, le principali informazioni ottenute da questi feeds.<br />
<br />
Altri miglioramenti in ArcGIS 10.2 includono un supporto ottimizzato per l'utilizzo in campo (quindi tramite dispositivi di tipo Mobile) di funzionalità enterprise, nuovi tool di geoprocessing, supporto per nuovi formati dati e database, una migliorata ricerca delle capabilites per raster e imagery. <br />
Completano il quadro, il rilascio di nuove applicazioni mobile e nuovi aggiornamenti per SDK e API.<br />
<br />
Nei seguenti paragrafi, organizzati per differenti aree funzionali, sono riassunte le principali novità introdotte con la 10.2 (ogni sezione include i link per eventuali approfondimenti).<br />
<br />
<span style="font-size: large;">Geoprocessing</span><br />
<br />
Sono presenti nuovi tool, miglioramenti a quelli esistenti e nuove funzioni ArcPy.<br />
<br />
<em><strong>Tool nuovi o perfezionati</strong></em><br />
I seguenti tool di geoprocessing sono stati aggiunti o migliorati in ArcGIS 10.2:<br />
<br />
<strong>3D Analyst toolbox</strong><br />
<ul>
<li>Il nuovo toolset <strong>CityEngine,</strong> nella toolbox 3D Analyst, include due nuovi tool di geoprocessing per processare e visualizzare dati 3D utilizzando le capabilities incluse in CityEngine:<blockquote dir="ltr" style="margin-right: 0px;">
<div>
- Il tool <a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q9000000n9000000.htm" target="_blank">Feature From CityEngine Rules</a> crea geometrie multipatch da feature 2D o 3D utilizzando regole create in CityEngine. Questo consente di generare modelli dettagliati 3D da ArcGIS;</div>
- il tool <a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q9000000np000000.htm" target="_blank">Export To 3D Web Scene</a> esporta documenti ArcScene in formato CityEngine Web Scene (.3ws), in modo da essere caricati e condivisi tramite ArcGIS Online (le Web Scene possono essere viste con browser WebGL compliant). </blockquote>
</li>
<li>il toolset <strong>Visibility </strong>contiene un nuovo tool per l'analisi di visibilità: tool <a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q9000000nn000000.htm" target="_blank">Intervisibility</a>;</li>
<li>il tool <a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q90000003p000000.htm" target="_blank">Raster To TIN</a> considera ora l'<a href="http://resources.arcgis.com/en/help/main/10.2/001w/001w00000009000000.htm" target="_blank">output extent</a> nelle impostazioni di ambiente;</li>
<li>il tool <a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q90000002p000000.htm" target="_blank">Construct Sight Lines</a> include un nuovo parametro, <em>Output The Direction,</em> che aggiunge due attributi all'output delle linee di vista per indicare la direzione: AZIMUTH e VERT_ANGLE (angolo verticale).</li>
</ul>
<strong>Cartography toolbox</strong><br />
<ul>
<li>Il tool <a href="http://resources.arcgis.com/en/help/main/10.2/0070/007000000047000000.htm" target="_blank">Delineate Built-Up Areas<strong></strong></a> include un nuovo parametro, <strong>Minimum Building Count</strong>, funzionale al controllo del minimo numero di edifici da considerare per generare la rappresentazione poligonale di un centro abitato.</li>
</ul>
<strong>Conversion toolbox</strong><br />
<ul>
<li>Un nuovo <a href="http://resources.arcgis.com/en/help/main/10.2/0012/001200000056000000.htm" target="_blank">Excel toolset</a> è stato aggiunto per convertire fogli Excel in tabelle e viceversa;</li>
<li>un nuovo <a href="http://resources.arcgis.com/en/help/main/10.2/0012/001200000059000000.htm" target="_blank">JSON toolset</a> è stato aggiunto per convertire feature con una rappresentazione Json e viceversa;</li>
<li>il nuovo tool <a href="http://resources.arcgis.com/en/help/main/10.2/0012/001200000053000000.htm" target="_blank">Multipatch to Raster</a> consente di convertire un dataset Multipatch a raster surface.</li>
</ul>
<strong>Data Management toolbox</strong><br />
<br />
Il Data Management toolbox include ora un nuovo <a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000018v000000.htm" target="_blank">Archiving toolset</a>, con la possibilità di attivare o disattivare la funzione di <em>archiving</em> in un geodatabase di tipo enterprise.<br />
Al raster toolset, invece, sono stati apportate le seguenti modifiche.<br />
<ul>
<li>aggiunti i seguenti tool:</li>
<ul>
<li>Il tool <a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000018s000000.htm" target="_blank">Compute Pansharpen Weights</a> calcola i pesi di pan-sharpening per set di pan-sharpening dataset;</li>
<li>il tool <a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000018r000000.htm" target="_blank">Merge Mosaic Dataset Items</a> unisce elementi mosaic dataset nella stessa riga;</li>
<li>il tool <a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000018q000000.htm" target="_blank">Split Mosaic Dataset Items</a> divide degli elementi mosaic dataset che sono stati uniti precedentemente;</li>
</ul>
<li>il tool <a href="http://resources.arcgis.com/en/help/main/10.2/0017/001700000165000000.htm" target="_blank">GeoTagged Photos To Points</a> ora registra le informazioni sulla direzione di ripresa di una foto quando tale funzione è supportata dal dispositivo utilizzato. La feature class di output avrà un nuovo campo <em>Direction, </em>con valori da 0 a 359.99 per indicare la direzione del dispositivo nel momento di acquisizione del fotogramma;</li>
<li>ai seguenti tool sono stati aggiunti nuovi parametri di impostazione:</li>
<ul>
<li><a href="http://resources.arcgis.com/en/help/main/10.2/0017/001700000155000000.htm" target="_blank">Alter Mosaic Dataset Schema</a> - parametro: <em>editor_tracking;</em></li>
<li><a href="http://resources.arcgis.com/en/help/main/10.2/0017/001700000089000000.htm" target="_blank">Build Seamlines</a> - parametro <em>blend_width_units;</em></li>
<li><a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000009n000000.htm" target="_blank">Clip</a> - parametro <em>maintain clipping_extent;</em></li>
<li><a href="http://resources.arcgis.com/en/help/main/10.2/0017/001700000161000000.htm" target="_blank">Set Mosaic Dataset Properties</a> - parametro <em>data_source_type</em> e <em>minimum_pixel_contribution;</em></li>
<li><a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000008v000000.htm" target="_blank">Synchronize Mosaic Dataset</a> - parametro <em>skip_existing_items.</em></li>
</ul>
</ul>
<strong>Data Reviewer toolbox</strong><br />
<br />
Il Data Reviewer toolbox include un nuovo tool: <a href="http://resources.arcgis.com/en/help/main/10.2/0108/010800000008000000.htm" target="_blank">Delete Reviewer Session.</a> <br />Questo tool rimuove una o più sessioni Reviewer e tutti i record associati ad esso. Utilizzando questo tool assieme ad altri tool di Reviewer, come <a href="http://resources.arcgis.com/en/help/main/10.2/0108/010800000006000000.htm" target="_blank">Create Reviewer Session</a> e <a href="http://resources.arcgis.com/en/help/main/10.2/0108/010800000007000000.htm" target="_blank">Execute Reviewer Batch Job</a>, consente di automatizzare flussi di controllo qualità.<br />
<br />
<strong>Geostatistical Analyst</strong><br />
<br />
La nuova classe ArcPy <a href="http://resources.arcgis.com/en/help/main/10.2/018z/018z000000n8000000.htm" target="_blank">GeostatisticalDatasets</a> può essere utilizzata per automatizzare interpolazioni di geostatistica, fornendo meccanismi per applicare parametri di interpolazione a nuovi dataset.<br />
<br />
<strong>Spatial Analyst toolbox</strong><br />
<br />
Con il tool <a href="http://resources.arcgis.com/en/help/main/10.2/009z/009z000000zr000000.htm" target="_blank">Visibility</a> è fornito un nuovo e più completo modo di analizzare le posizioni visibili su una <em>surface</em>. <br />Uno dei principali benefici di questo nuovo tool ,rispetto ai precedenti tool <em>Observer Po</em>ints e <em>Viewshed</em>, è la possibilità di definire parametri di visibilità direttamente nel tool, in alternativa ai valori "statici" previsti nella tabella delle feature di input dell'osservatore.<br />
Il supporto multicore è stato aggiunto ai seguenti tools: <a href="http://resources.arcgis.com/en/help/main/10.2/009z/009z000000sr000000.htm" target="_blank">Reclassify</a>, <a href="http://resources.arcgis.com/en/help/main/10.2/009z/009z000000rq000000.htm" target="_blank">Weighted Overlay</a>, <a href="http://resources.arcgis.com/en/help/main/10.2/009z/009z000000rr000000.htm" target="_blank">Weighted Sum</a>, <a href="http://resources.arcgis.com/en/help/main/10.2/009z/009z000000w7000000.htm" target="_blank">Zonal Statistics</a>, <a href="http://resources.arcgis.com/en/help/main/10.2/009z/009z000000w8000000.htm" target="_blank">Zonal Statistics As Table</a>.<br />
<br />
<strong>Spatial Statistics toolbox</strong><br />
E' stato aggiunto un nuovo tool: <a href="http://resources.arcgis.com/en/help/main/10.2/005p/005p00000058000000.htm" target="_blank">Optimized Hot Spot Analysis</a>.<br />
Ai to <a href="http://resources.arcgis.com/en/help/main/10.2/005p/005p00000006000000.htm" target="_blank">Cluster and Outlier Analysis</a> e <a href="http://resources.arcgis.com/en/help/main/10.2/005p/005p00000010000000.htm" target="_blank">Hot Spot Analysis</a>, inoltre, è stato aggiunto il parametro <a href="http://resources.arcgis.com/en/help/main/10.2/005p/005p00000006000000.htm#ESRI_SECTION1_2C5DFC8106F84F988982CABAEDBF1440" target="_blank">Apply False Discovery Rate (FDR) Correction</a>.<br />
<br />
<strong>ArcPy</strong><br />
<ul>
<li>Ora è possibile automatizzare la pubblicazione di servizi di geocode utilizzando Python. La funzione <a href="http://resources.arcgis.com/en/help/main/10.2/018v/018v00000095000000.htm" target="_blank">CreateGeocodeSDDraft</a> può essere utilizzata per creare la definizione del servizio dal proprio address locator;</li>
<li>è possibile creare un database SQLite, che contenga il tipo Esri ST_Geometry o SpatialLite, utilizzando la nuova funzione workspace <a href="http://resources.arcgis.com/en/help/main/10.2/018v/018v00000096000000.htm" target="_blank">CreateSQLiteDatabase</a>.</li>
</ul>
<strong>Funzioni ArcPy</strong><br />
<strong></strong><br />
<em><strong><u>Funzioni raster</u></strong></em><br />
<a href="http://resources.arcgis.com/en/help/main/10.2/018v/018v00000023000000.htm" target="_blank">RasterToNumPyArray</a> ora supporta la conversione diretta di raster multiband in array a tre dimensioni numPy. Più specificatamente:<br />
<ul>
<li>Se l'istanza del raster di input è basata su raster multibanda, la funzione restituisce un array a tre dimensioni (3D), dove la lunghezza della prima dimensione rappresenta il numero di bande. L'array 3D avrà le dimensioni (bande, righe, colonne);</li>
<li>se l'istanza del raster di input è basata su un singolo raster o è una specifica banda di un raster multibanda, la funzione restituisce un array a due dimensioni con le dimensioni (righe, colonne).</li>
</ul>
<a href="http://resources.arcgis.com/en/help/main/10.2/018v/018v0000005n000000.htm" target="_blank">NumpyArrayToRaster</a> supporta la conversione diretta di array numPy a tre dimensioni a raster multibanda.<br />
<ul>
<li>Se l'array di input ha tre dimensioni (3D) la funzione restituisce un raster multi banda, dove il numero di bande è la lunghezza della prima dimensione e la dimensione del raster è definita dalla seconda e terza dimensione (bande, righe,colonne)</li>
<li>se l'array di input ha due dimensioni, la funzione restituisce un raster a banda singola , dove la dimensione del raster è definita dalle dimensioni (righe, colonne).</li>
</ul>
Da notare che, se l'array di input ha tre dimensioni e la prima dimensione ha la dimensione 1, la funzione restituisce un raster a banda singola.<br />
<br />
<strong>Geoprocessing services</strong><br />
<br />
I tool di geoprocessing in ArcGIS Server Linux sono in media più veloci del 25 percento per l'ottimizzazione file di input e output.<br />
<br />
<span style="font-size: large;"></span><br />
<span style="font-size: large;">Accesso ad ArcGIS Online tramite ArcGIS for Desktop</span><br />
<br />
L'accesso in ArcGIS Online (AOL) consente di entrare nei dati e nelle applicazioni personali, in quelli delle nostre organizzazioni, nei contenuti pubblicati da Esri, dalle community e da altri utenti.<br />
L'accesso, inoltre, è sempre necessario per pubblicare e condividere risorse in ArcGIS Online.<br />
<br />
Per questo motivo, la nuova versione include miglioramenti significativi per facilitare l'accesso ad ArcGIS Online a partire da applicazioni ArcGIS for Desktop, compresi interventi funzionali a garantire maggiore sicurezza e la possibilità di impostare la frequenza con la quale ArcGIS for Desktop controlla la connessione ad ArcGIS Online.<br />
<br />
L'accesso da una applicazione ArcGIS for Desktop avviene sempre allo stesso modo, indipendentemente dal fatto che si acceda al sito di ArcGIS Online o ad un portale locale. <br />Molti utenti accederanno con un account ArcGIS: un <a href="https://www.arcgis.com/home/signin.html" target="_blank">account pubblico ArcGIS</a> oppure uno riconducibile ad una sottoscrizione <em>ArcGIS Online for organization</em>.<br />
Gli amministratori della sottoscrizione potranno impostare altre forme di autenticazione, ad esempio consentendo di accedere ad ArcGIS Online utilizzando la propria login di Windows. Come ulteriore garanzia di sicurezza, esiste anche la possibilità di consentire gli accessi tramite una <em>security card</em>. <br />
In assenza di impostazioni particolari, ArcGIS for Desktop si connette automaticamente ad ArcGIS Online. Per accedere ad un portale specifico o utilizzare i metodi di sicurezza di cui sopra, l'amministratore deve inserire l'URL del portale nel <a href="http://resources.arcgis.com/en/help/main/10.2/0003/00030000001p000000.htm" target="_blank">Manage ArcGIS Portal Connection dialog box</a>.<br />
<br />
L'impostazione standard prevede che ArcGIS for Desktop controlli automaticamente la connessione con AOL solo all'avvio dell'applicazione (es: ArcMap). <br />
In presenza di connessioni instabili, ad esempio quando si lavora all'aperto e il segnale è debole, è auspicabile modificare questa impostazione, così che l'applicazione verifichi la connessione ad intervalli regolari. In questo modo saremo allertati qualora la connessione non fosse più disponibile, impedendoci di accedere a funzionalità AOL. <br />
Per contro, nell'eventualità di operare completamente offline, potremo impostare ArcGIS in modo che non effettui alcun controllo.<br />
Per impostare la frequenza di controllo, si agisce attraverso le proprietà di <em>ArcGIS Connection Utility</em> nel <em>system tray</em> di Windows.<br />
<br />
<span style="font-size: large;">Mapping</span><br />
<br />
<strong>Compatibilità tra documenti ArcGIS 10.1 e 10.2</strong><br />
<br />
Documenti di ArcMap (MXD), ArcScene (SXD) e ArcGlobe (3dd), a prescindere dal fatto che siano creati o modificati con la versione 10.1 o con la 10.2, risulteranno utilizzabili con entrambe le versioni, senza alcuna necessità di effettuare conversioni. In particolare possiamo aprire con ArcGIS 10.1 tutti progetti MXD creati o modificati in ambiente 10.2.<br />
<br />
<strong>Bing Maps</strong><br />
<br />
L'uso gratuito delle Bing Maps in ambiente ArcGIS non sarà più consentito.<br />
Con ArcGIS 10.2, in particolare, sarà necessario richiedere una <a href="https://www.bingmapsportal.com/" target="_blank">license key direttamente a Microsoft</a>, requisito obbligatorio per utilizzare qualsiasi basemap della<em> Bing Map collection</em>. <br />
<br />
Se un amministratore registra una chiave Bing Maps con un account di ArcGIS Online organizations, tutti gli utenti dell'organizzazione possono visualizzarele Bing Maps, previa autenticazione, in ambiente ArcGIS Desktop.<br />Si può inserire la chiave attraverso l'applicazione <em>Set Bing Ke</em>y (SetBingKey.exe), che risiede nella cartella \bin dove è installato ArcGIS.<br />
<br />
Come valida alternativa al noto servizio <em>Bing Map Aerial</em>, si consiglia l'utilizzo della basemap <em>ArcGIS World Imagery </em>, che raccoglie riprese da satellite o da aeree con risoluzioni estremamente dettagliate su molte parti del mondo.<br />
<br />
<strong>Reports</strong><br />
<br />
I tool di reporting di ArcGIS ora consentono di creare personalizzate mailing label da dati di un layer o di una tabella. Per maggiori dettagli vedere <a href="http://resources.arcgis.com/en/help/main/10.2/004v/004v00000023000000.htm" target="_blank">Creating mailing labels</a>.<br />
<br />
<span style="font-size: large;">Geodata</span><br />
<strong></strong><br />
<strong>Geodatabase e database</strong><br />
<strong></strong><br />
E' stato aggiunto il supporto<strong> </strong>per IBM Netezza 7.0 e INZA 2.5 che include il Netezza Spatial Esri Package. Il Netezza Spatial Esri Package è un data type ST_Geometry piuttosto che un varchar.<br />
E' stato aggiunto il supporto per PostgreSQL 9.2. Quando si crea un geodatabase si deve utilizzare le versione 9.2 delle librerie st_geometry o installare ST_Geometry in un database PostgreSQL 9.2.<br />
Le librerie st_geometry 9.2 possono essere trovate nella directory DatabaseSupport nelle directory di installazione client di ArcGIS.<br />
A partire da ArcGIS 10.2 è possibile connettersi e lavorare con semplici feature data in un database <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//019v0000001t000000" target="_blank">Teradata</a> o in un database <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//019v0000001w000000" target="_blank">SQLite</a>. Questo consente di visualizzare ed analizzare dati spaziali che sono memorizzati in questi database senza doverli spostare in un geodatabase. Con ArcGIS 10.2 in ArcPy abbiamo una funzione che permette di creare database SQLite. Per maggiori informazioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//018v00000096000000" target="_blank">CreateSQLiteDatabase</a>.<br />
I seguenti cambi in ArcGIS 10.2 influenzano le viste versionate:<br />
<ul>
<li>Il tool di geoprocessing <em>Create Versioned View</em> non è più disponibile; comunque gli esistenti script e modelli che utilizzano il tool lavorano ancora;</li>
<li>è possibile creare una vista versionata su un dataset versionato cliccando con il tasto destro in ArcCatalog su <em>Manage</em> e cliccando su <em>Enable SQL Access. Enable SQL Access</em> sostituisce la voce di menu <em>Create Versioned View;</em></li>
<li>le viste versionate create in ArcGIS 10.2 o nelle release successive seguono la convenzione di nome <nome tabella>_evw.</li>
</ul>
Archiving geodatabase è ora supportato su tabelle che non sono registrate come versionate. Quando la tabella non versionata è abilitata per l'archiving, viene creata una vista archivio. Utilizziamo la vista archivio per aggiornare, inserire o eliminare righe da una tabella tramite SQL abilitata all'archivio. Se abbiamo bisogno di creare una vista archivio su una tabella dopo che è stata abilitata per l'archiving ( ad esempio, se non abbiamo avuto i privilegi per creare viste quando fu abilitato l'archiving) possiamo utilizzare <em>Manage</em> -> <em>Enable SQL Access</em> in ArcGIS for Desktop.<br />
Dopo che abbiamo creato tabelle o feature class, ora possiamo modificare la definizione dei campi in base alle nostre esigenze. Ad esempio, possiamo ridefinire la definizione di campo da not nullable a consentire i valori null. A partire da ArcGIS 10.2 for Desktop, possiamo modificare alcune proprietà dei campi in tabelle e feature classe esistenti. Per maggiori dettagli vedere <a href="http://resources.arcgis.com/en/help/main/10.2/index.html#//003n00000100000000" target="_blank">Modifying field properties</a><br />
Per determinare l'esatta versione del geodatabase, <strong>Upgrade Status</strong> nella tab <em>General</em> della finestra di dialogo <em>Database Properties</em> mostrerà la versione e il service pack o il livello di patch della 10.2 o delle release successive del geodatabase al quale ci si sta connettendo.<br />
Dalla 10.2 possiamo pubblicare dati dal nostro database DB2, Informix, Oracle, PostgreSQL o SQL Server come feature service dal nostro ArcGIS Server. Vedere <a href="http://resources.arcgis.com/en/help/main/10.2/016w/016w0000005s000000.htm#ESRI_SECTION2_2FA990CCDBE84A55A59B77DCD6623EA1" target="_blank">Publishing feature services from databases</a><br />
<br />
<strong>Raster</strong><br />
La ricerca di immagini sul Desktop era precedentemente limitata perché basata solo sul formato. La finestra <strong>Search </strong>ora è stata estesa per abilitare la ricerca di immagini basate sui metadati. L'indice di ricerca può essere configurato per cercare in deteminati percorsi per prodotti raster, mosaic dataset ed elementi in un mosaic dataset e dai quali estrarrà le chiavi di ricerca dai metadati. Una volta indicizzato, l'utente può velocemente cercare immagini di uno specifico sensore, che coprono una determinata area con specifici tag nei metadati come la copertura nuvolosa. Dai risultati della ricerca è possibile aggiungere l'immagine su ArcGIS for Desktop o in un mosaic dataset. Per maggiori dettagli vedere <a href="http://resources.arcgis.com/en/help/main/10.2/009t/009t0000025s000000.htm" target="_blank">Searching for images in ArcGIS</a>.<br />
E' stato aggiunto il supporto per tre nuovi tipi di raster: DMCii, Pleiades e SPOT6. Inoltre, ArcGIS 10.2 supporta una nuova estensione che consente di aggiungere vari tipi di raster per Immagini Satellitari Cinesi un dataset mosaic. Per maggiori informazioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/009t/009t00000259000000.htm" target="_blank">Raster Types for Chinese Satellite Imagery</a>.<br />
Sono presenti tre nuovi tool di geoprocessing per i raster: <a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000018r000000.htm" target="_blank">Merge Mosaic Dataset Items</a>, <a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000018q000000.htm" target="_blank">Split Mosaic Dataset Items</a> e <a href="http://resources.arcgis.com/en/help/main/10.2/0017/00170000018s000000.htm" target="_blank">Compute Pan-sharpening Weights</a>. Ci sono anche molti aggiornamenti per gli esistenti tool di geoprocessing per i raster.<br />
<a href="http://resources.arcgis.com/en/help/main/10.2/009t/009t0000025p000000.htm" target="_blank">Local function</a> è una nuova funzione raster che consente di eseguire operazioni binarie, condizionali, logiche, matematiche e statistiche basate sul pixel. Per utilizzare questa funzione è richiesta l'estensione Spatial Analyst.<br />
L'operatore Sum è stato aggiunto ad alcuni tool e funzioni che utilizzano il mosaico. L'operatore Sum consente di aggiungere i valori di pixel di tutte le celle che si sovrappongono all'interno dell'ouput del mosaico.<br />
<strong></strong><br />
<strong>CAD</strong><br />
E' stato aggiunto il supporto alla lettura diretta per il formato 19.0 DWG AutoCAD 201, il nuovo formato introdotto da Autodesk per tutti i prodotti 2013.<br />
Una compatibilità certamente apprezzata da chi utilizza spesso, in ambiente ArcGIS, layer basati su disegni in formato DWG.<br />
<br />
<span style="font-size: large;">Editing</span><br />
<strong></strong><br />
<strong>Parcel editing</strong><br />
<strong></strong><br />
<strong><em>Creazione di nuove particelle</em></strong><br />
Quando si crea una nuova particella, possiamo cliccare su <em>Load Cadastral XML</em> (<em> </em><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx5lG26DcOb7pYP1aLNSXEEI1Pr3bVa801SpMO4_mepEZjzDNGlV42LY4kjgmGhGgtUg4gAFmmvraHA4JmCNW4ZZKzqSrLIV924er0nMokYETwo8uEXS1QErLmHJY5jr6mZ_8nUbaC5YoV/s1600/LoadCadastralXML.png" /> ) sulla finestra di dialogo <em>Parcel Details</em> per appendere una particella traversa da un file xml catastale in una griglia <em>Lines</em>. La funzionalità di caricamento XML catastale appende un singolo set di linee di particelle traverse.<br />
Eventuali attributi della linea salvati con il file XML catastale sono anch'essi appesi nei corrispondenti attributi nella griglia <em>Lines.</em><br />
<br />
<em><strong>Storico della particella</strong></em><br />
Quando si crea uno nuovo piano di lavoro, se l'attributo <strong>LegalDate </strong>è inserito per gli attributi del piano di lavoro, sarà copiato nell'attributo <strong>LegalStartDate </strong>delle nuove particelle create nel piano. L'attributo <strong>LegalDate</strong> è anche copiato nell'attributo <strong>LegalEndDate</strong> delle particelle che diventano storiche come risultato di un'operazione, ad esempio, da una fusione di particelle per creare una nuova particella.<br />
<br />
<span style="font-size: large;">Servizi</span><br />
<span style="font-size: large;"></span><br />
<strong>I servizi GIS sono supportati sul Portal for ArcGIS</strong><br />
<br />
Portal for ArcGIS è ora un prodotto che può essere distribuito nella propria rete privata per condividere mappe, applicazioni ed altre informazioni geografiche con altri membri dell'organizzazione. Il contenuto che si condivide è distribuito agli utenti dell'organizzazione attraverso un sito web, che può essere personalizzato per impostare il <em>look and feel</em> della propria organizzazione. <br />
Possiamo configurare ArcGIS for Server 10.2 per lavorare con Portal for ArcGIS. Questo consente di ospitare servizi feature o di mappa su ArcGIS Server che possono essere disponibili agli utenti nell'organizzazione tramite il portale. Possiamo anche utilizzare i servizi di print e geocode per supportare mappe e applicazioni degli utenti create nel Portal for ArcGIS.<br />
<br />
<strong>Backup e restore della configurazione del site</strong><br />
<strong></strong><br />
Ora possiamo fare il backup della configurazione del site ed utilizzarla per ripristinare le impostazioni se il site va in offline inaspettatamente o ripristinare da modifiche effettuate successivamente al backup. Le operazioni di backup e restore sono chiamate attraverso utility da riga di comando o attraverso le API ArcGIS Server Administrator. Le informazioni di backup sono memorizzate in un singolo file al quale fare riferimento quando eseguiamo un'operazione di restore.<br />
Per maggiori dettagli vedere <a href="http://resources.arcgis.com/en/help/main/10.2/0154/015400000619000000.htm" target="_blank">Backing up and restoring your ArcGIS Server site configuration</a>.<br />
<br />
<strong>Pubblicazione di servizi di tipo feature da database</strong><br />
<br />
Prima della 10.2 si poteva pubblicare un servizio di mappa con abilitato il feature access (un servizio feature) in ArcGIS Server se il database era contenuto in un geodatabase. Dalla 10.2 possiamo pubblicare servizi feature abilitati all'editing da DBMS supportati. Per una lista dei database supportati e di tipi di dati spaziali vedere <a href="http://resources.arcgis.com/en/help/system-requirements/10.2/0151/01510000006w000000.htm" target="_blank">ArcGIS database managament system requirements</a>.<br />
A partire da ArcGIS 10.2, è consigliato utilizzare servizi feature ArcGIS Server per pubblicare dati da un database piuttosto che utilizzare servizi feature ArcGIS Spatial Data Server perché questi ultimi sono deprecati.<br />
<br />
<strong>Ora i servizi di mappa, feature e WFS utilizzano interrogazioni standardizzate</strong><br />
<strong></strong><br />
ArcGIS Server ora include un'opzione sulla sicurezza che 'forza' lo sviluppatore ad utilizzare interrogazioni SQL standardizzate quando lavora con servizi di mappa, feature, image e WFS attraverso REST e SOAP. Questo aiuta a prevenire attacchi di tipo SQL injection ed anche rende il lavoro più semplice allo sviluppatore per applicazioni che interrogano i servizi ArcGIS Server. Le interrogazioni standardizzate sono abilitate di default ma possono essere disabilitate dall'amministrazione del server. Per maggiori informazioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/0154/015400000641000000.htm" target="_blank">About standardized queries</a><br />
<br />
<strong>Il nuovo servizio CachingControllers migliora la stabilità quando multipli job di cache vengono inviati per l'esecuzione contemporaneamente</strong><br />
<br />
Un nuovo servizio di geoprocessing <strong>CachingControllers</strong> è preconfigurato nella cartella System. Questo servizio gestisce tutti i job elaborati dal servizio <strong>CachingTools</strong>.<br />
Il servizio CachingControllers può aiutare il server ad evitare instabilità quando molti pubblicatori notificano job di caching contemporaneamente. Il massimo numero di istanze che consente il servizio di CachingControllers rappresenta il numero massimo di job di caching che si può eseguire contemporaneamente. Job ulteriori saranno accodati.<br />
<br />
<strong>Miglioramenti per ArcGIS Server Manager</strong><br />
<br />
ArcGIS Server Manager include miglioramenti che possono aiutare l'amministratore del site ArcGIS Server:<br />
<ul>
<li>L'amministratore può prevenire il fatto che i pubblicatori copino i dati automaticamente al server quando pubblicano, disabilitando la copia dei dati dal Manager. Precedentemente, questa funzionalità era solo esposta attraverso l'ArcGIS Server Administrator Directory. Per le complete istruzioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/0154/01540000060n000000.htm" target="_blank">Disabling automatic data copying when publishing to the server</a>; </li>
<li>una nuova finestra di dialogo - <strong>Service Workspaces</strong> - è stata aggiunta ad ArcGIS Server Manager per aiutare a tracciare quali cartelle o database i servizi stanno utilizzando. Per maggiori informazioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/0154/01540000060t000000.htm" target="_blank">Reviewing service workspaces in Manager</a>;</li>
<li>il pulsante <strong>Restart</strong> è stato rimosso dal modulo <strong>Manage Services</strong> nel Manager. In aggiunta il pulsante <strong>Stop</strong> è attivo solo per un servizio che è in esecuzione e il pulsante <strong>Start</strong> è attivo solo quando il servizio è fermo. Per fare un restart, cliccare <strong>Stop</strong> e poi cliccare <strong>Start</strong>.</li>
</ul>
<strong>Supporto per data source OLE DB</strong><br />
<br />
Le connessioni OLE DB forniscono un accesso uniforme ai dati da molte sorgenti ma sono connessioni con dati non spaziali. In ArcGIS for Server 10.2 possiamo ora utilizzare queste sorgenti dati nei servizi. Quando pubblichiamo possiamo avere i dati OLE DB copiati al server come parte dell'azione di pubblicazione, in alternativa possiamo registrarli con il server per evitare la copia dei dati. Per maggiore dettagli vedere i seguenti link:<br />
<ul>
<li><a href="http://resources.arcgis.com/en/help/main/10.2/0154/015400000505000000.htm" target="_blank">About registering your data with the server</a></li>
<li><a href="http://resources.arcgis.com/en/help/main/10.2/0154/0154000003rn000000.htm" target="_blank">Copying data to the server automatically when publishing</a></li>
</ul>
<span style="font-size: large;"></span><br />
<span style="font-size: large;">Estensioni</span><br />
<br />
<strong>Estensione ArcGIS 3D Analyst</strong><br />
<strong></strong><br />
<em><strong>LAS dataset</strong></em><br />
In ArcGIS 10.2 quando le statistiche sono calcolate, viene creato un<a href="http://resources.arcgis.com/en/help/main/10.2/015w/015w0000006v000000.htm#ESRI_SECTION1_CAB81C24D48F4B89A26A195F3B1FEF51"> LAS auxiliary file (.lasx)</a> per ogni LAS file. Questo file memorizza le informazioni statistiche calcolate ed un nuovo indice spaziale per ogni LAS file. Gli indici spaziali forniscono un accesso più veloce ai dati lidar e migliorano complessivamente le prestazioni del dataset LAS. I miglioramenti sono particolarmente efficaci per file LAS molto grandi (ad esempio più grandi di 500Mb) e per organizzazioni che possiedono un repository centrale LAS che è esposto su una rete.<br />
<br />
<strong><em>3D Web Scenes</em></strong><br />
Ora i documenti ArcScene possono essere esportati come 3D Web Scenes utilizzando il nuovo <a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q9000000n8000000.htm">toolset City Engine</a>. L'output 3D Web Scenes (.3ws) è un nuovo tipo di elemento ArcGIS Online per ArcGIS 10.2 e può essere facilmente caricato e condiviso in ArcGIS Online, Portal o in un proprio Web Server (<a href="http://www.arcgis.com/home/item.html?id=38fede3935a440e49cf316dcae6aae47">CityEngine WebViewer</a>). In questo modo possiamo visualizzare e condividere i dati 3D in un web browser, consentendo una più facile comunicazione di contenuti 3D complessi verso gli altri.<br />
<br />
<strong><em>Contenuti 3D basati su regole</em></strong><br />
ArcGIS 10.2 consente agli utenti ArcGIS 3D Analyst di utilizzare <a href="http://resources.arcgis.com/en/help/main/10.2/00q9/00q9000000n9000000.htm">rule package create in CityEngine</a> 2013 con i propri esistenti flussi di lavoro utilizzando geoprocessing. Le multipatch sono generati da feature 2D e 3D applicando le regole CityEngine.<br />
<strong></strong><br />
<strong>Estensione ArcGIS GeoEvent Processor for Server</strong><br />
<br />
L'estensione ArcGIS GeoEvent Processor for Server è una nuova estensione per ArcGIS for Server che abilita flussi di dati GIS in real time. L'estensione consente di connettersi praticamente con qualsiasi tipo di flusso di dati ed allertare automaticamente il personale quando si verificano certe condizioni, il tutto in tempo reale. Il GeoEvent Processor rivoluziona le nostre applicazioni GIS, aiutando a rispondere più velocemente, con notevole precisione sempre ed ovunque quando si verifica un cambiamento.<br />
Per maggiori informazioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/0154/015400000655000000.htm">What is the ArcGIS GeoEvent Processor for Server extension?</a><br />
<br />
<strong>Estensione ArcGIS Schematics</strong><br />
<strong></strong><br />
<em><strong>Packing di dati schematic e copia di dati schematic quando si pubblica un servizio schematic</strong></em><br />
I Map package (.mpk) sono stati migliorati per supportare i layer schematic diagram. Questo significa che a partire dal ArcGIS 10.2 for Desktop, possiamo creare package schematic diagram che sono contenuti in un documento di mappa. Per maggiori informazioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/004z/004z000000s1000000.htm">About packaging schematic diagrams</a>.<br />
Grazie a questo miglioramento, ora gli schematic data possono anche essere copiati nel server quando si pubblica. Inoltre ora questo è il comportamento di default quando i dati schematic non sono registrati con il server. Per maggiori informazioni vedere <a href="http://resources.arcgis.com/en/help/main/10.2/0154/0154000004rv000000.htm">About publishing schematics data</a>.<br />
<br />
<strong><em>Modifiche di funzioni per migrazione ed esportazione schematic dataset</em></strong><br />
Nelle versioni Schematics precedenti alla 10.2 quando si migrava e si esportava schematic dataset, non c'era modo di filtrare gli schematic diagram che si voleva migrare o esportare. Schematic 10.2 fornisce nuove funzioni per migrare ed esportare schematic dataset che consentono di filtrare il set di diagram che desideriamo migrare o esportare.<br />
<br />
<br />
<strong>Estensione Data Interoperability</strong><br />
<br />
E' stato aggiunto il supporto per U.S. Census Bureau TIGER/GML, Google Spreadsheed e altri 14 formati di file. Per una completa lista dei formati supportati vedere <a href="http://resources.arcgis.com/en/help/main/10.2/004m/004m0000002m000000.htm">Supported formats with the Data Interoperability extension</a> .<br />
<br />
<span style="font-size: large;">Soluzioni per l'industria</span><br />
<br />
<strong>Geocoding</strong><br />
<strong></strong><br />
Ora è supportata la geocodifica di una tabella di indirizzi con il servizio di geocode ArcGIS Online World. Possiamo utilizzare il servizio per geocodificare indirizzi e località su 100 paesi con singola linea. Per utilizzare il servizio di geocodifica batch è richiesta una sottoscrizione ArcGIS Online for organizations. Una volta che si possiede la sottoscrizione possiamo impostare una connessione al servizio di geocode World. Vedere per maggiori informazioni ed istruzioni <a href="http://resources.arcgis.com/en/help/main/10.2/0025/00250000004v000000.htm">Geocoding a table of addressed using ArcGIS Online geocode service</a>. Se abbiamo bisogno di utilizzare la versione precedente dei servizi di geocode ArcGIS Online, possiamo impostare una connessione al servizio <a href="http://tasks.arcgisonline.com/arcgis/services">http://tasks.arcgisonline.com/arcgis/services</a>.<br />
<br />
<br />
<strong>ArcGIS for 3D Cities</strong><br />
<br />
La soluzione ArcGIS for 3D Cities aiuta a pianificare e capire la city fornendo basi per la gestione, visualizzazione, l'analisi e la condivisione di spazi urbani 3D. Organizza tutti i dati della city come edifici, zonizzazioni, servizi e di arredo urbano come alberi, lampioni in un modello di informazioni ben definito e con un set di strumenti specializzati e di flussi di lavoro.<br />
Inoltre abbiamo il vantaggio di potenti strumenti di geoprocessing 3D in ArcGIS 10.2 per la creazione di contenuti e di analisi urbane 3D come ad esempio l'impatto visuale.<br />
<br />
<br />
<span style="font-size: large;">GIS Mobile</span><br />
<strong></strong><br />
<strong>Aplicazioni</strong><br />
<strong></strong><br />
Le seguenti sono le nuove app rilasciate a partire da ArcGIS 10.1:<br />
<ul>
<li><a href="http://links.esri.com/whatsnew_opsdash102" target="_blank">Operations Dashboard for ArcGIS</a></li>
<li><a href="http://links.esri.com/whatsnew_collectorandroid102" target="_blank">Collector for ArcGIS (Android)</a></li>
<li><a href="http://links.esri.com/whatsnew_collectorios102" target="_blank">Collector for ArcGIS (iOS)</a></li>
</ul>
<br />
Vedere i seguenti argomenti per le nuove funzionalità nelle esistenti applicazioni mobile:<br />
<ul>
<li><a href="http://links.esri.com/whatsnew_androidapp102" target="_blank">ArcGIS application for Android</a></li>
<li><a href="http://links.esri.com/whatsnew_iosapp102" target="_blank">ArcGIS application for iOS</a></li>
<li><a href="http://links.esri.com/whatsnew_winmobapp102" target="_blank">ArcGIS for Windows Mobile</a></li>
<li><a href="http://links.esri.com/whatsnew_winphoneapp102" target="_blank">ArcGIS application for Windows Phone</a></li>
<li><a href="http://links.esri.com/whatsnew_arcpad102" target="_blank">ArcPad</a></li>
</ul>
<br />
<strong>API</strong><br />
<ul>
<li>Possiamo sviluppare app mobile con <a href="http://links.esri.com/whatsnew_flexsdk102" target="_blank">ArcGIS API for Flex</a>; per dettagli vedere <a href="http://links.esri.com/en/offcycle_flexmobile" target="_blank">Mobile applications with Flex</a>;</li>
<li>possiamo <a href="http://links.esri.com/en/offcycle_javascriptmobile" target="_blank">sviluppare pagine web per mobile</a> con <a href="http://links.esri.com/whatsnew_javascriptsdk102" target="_blank">ArcGIS API for Javascript</a> (vedere la cartella mobile). In alternativa possiamo sviluppare app mobile con un tool di terze parti;</li>
<li>per vedere che cosa c'è di nuovo nei nativi SDK per lo sviluppo di app mobile, vedere la seguente sezione.</li>
</ul>
<br />
<strong>SDK e API</strong><br />
<strong></strong><br />
<ul>
<li>Nuovi SDK sono stati rilasciati a partire dalla versione ArcGIS 10.1:</li>
<ul>
<li><a href="http://links.esri.com/whatsnew_mac_osx" target="_blank">ArcGIS Runtime SDK for OS X</a></li>
<li><a href="http://links.esri.com/whatsnew_qt" target="_blank">ArcGIS Runtime SDK for Qt</a></li>
<li><a href="http://links.esri.com/whatsnew_winrt" target="_blank">ArcGIS Runtime SDK for Windows Store apps</a></li>
</ul>
<li>vedere questi argomenti per vedere che cosa c'è di nuovo negli esistenti SDK mobile:</li>
<ul>
<li><a href="http://links.esri.com/whatsnew_winmobsdk102" target="_blank">ArcGIS Runtime SDK for Windows Mobile</a> (precedentemente denominato ArcGIS Mobile SDK)</li>
<li><a href="http://links.esri.com/whatsnew_arcpad102" target="_blank">ArcPad</a> (include il che cosa c'è di nuovo per gli sviluppatori)</li>
</ul>
<li>vedere questi argomenti per vedere che cosa c'è di nuovo negli SDK ArcGIS Runtime:</li>
<ul>
<li><a href="http://links.esri.com/whatsnew_androidsdk102" target="_blank">ArcGIS Runtime SDK for Android</a></li>
<li><a href="http://links.esri.com/whatsnew_iossdk102" target="_blank">ArcGIS Runtime SDK for iOS</a></li>
<li><a href="http://links.esri.com/whatsnew_javasdk102" target="_blank">ArcGIS Runtime SDK for Java</a> (Windows e Linux)</li>
<li><a href="http://links.esri.com/whatsnew_winphonesdk102" target="_blank">ArcGIS Runtime SDK for Windows Phone</a></li>
<li><a href="http://links.esri.com/whatsnew_wpfsdk102" target="_blank">ArcGIS Runtime SDK for WPF</a> (per Windows)</li>
</ul>
<li>vedere questi argomenti per vedere che cosa c'è di nuovo nelle Web API:</li>
<ul>
<li><a href="http://links.esri.com/whatsnew_flexsdk102" target="_blank">ArcGIS API for Flex</a></li>
<li><a href="http://links.esri.com/whatsnew_javascriptsdk102" target="_blank">ArcGIS API for Javascript</a></li>
<li><a href="http://links.esri.com/whatsnew_silverlight102" target="_blank">ArcGIS API for Silverlight</a></li>
</ul>
<li>questi argomenti hanno informazioni su che cosa c'è di nuovo in ArcObjects:</li>
<ul>
<li><a href="http://links.esri.com/whatsnew_aonetsdk102">.NET</a></li>
<li><a href="http://links.esri.com/whatsnew_aocpp102">C++</a></li>
<li><a href="http://links.esri.com/whatsnew_aojava102">Java</a></li>
</ul>
<li>per informazioni su altri cambiamenti e nuove caratteristiche per sviluppatori vedere questi argomenti:</li>
<ul>
<li><a href="http://links.esri.com/whatsnew_rest102">ArcGIS REST specification</a></li>
<li><a href="http://links.esri.com/whatsnew_sharepoint102">ArcGIS for SharePoint</a></li>
<li><a href="http://links.esri.com/whatsnew_gpdev102">Geoprocessing</a> (Python e ArcPy) </li>
</ul>
</ul>
<strong></strong><br />
<strong></strong><br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com2Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902007 9.255947099999957620.068166199999997 -32.052646900000042 71.1122352 50.564541099999957tag:blogger.com,1999:blog-8323071861123024882.post-12825206419185938932013-06-30T20:04:00.000+02:002013-07-23T10:59:51.432+02:00Dynamic layersUna delle più interessanti migliorie disponibili per i servizi di mappa rilasciate con la versione di ArcGIS for Server 10.1 è sicuramente l'introduzione dei dynamic layers.<br />
Pubblicando un servizio di mappa con il dynamic layer abilitato ci consente di modificare il renderer di un layer, riposizionare un layer rispetto agli altri od anche aggiungere un nuovo layer da uno dei workspace registrati con il servizio. E' evidente che così aumentiamo l'interazione che l'utente può avere con le mappe via web; ma evita anche allo sviluppatore, ad esempio per il renderer, di scriversi centinaia, se non migliaia, di linee di codice per calcolarsi breaks, applicare una color ramp e fare altre operazioni dovendosi scaricare sul client tutti i dati con in più il problema che il server potrebbe limitare l'operazione con la proprietà maxRecordCount.<br />
<br />
Ma vediamo come abilitare questa funzionalità nel nostro servizio di mappa e come ad esempio aggiungere un nuovo layer alla mappa.<br />
Nel Service Editor selezioniamo sotto <strong>Capabilities</strong> la voce <strong>Mapping</strong> e sul pannello di destra clicchiamo <strong><em>Allow per request modification of layer order symbology</em></strong> così abilitiamo i dynamic layer per il servizio di mappa.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBY69UzKWz2yNNRaEMDbNlhJux4dC2K_aX9DlbmsUYVg3029Mfhnw2w0MppDP7UJ1Fp5Z1DzWZR2CaVhH02qcwoXMytaMNPJXT-ZDntL3DHpcsmTlXpqwAkYJLybeloloMHvLX57Na7uSE/s1600/dynLayer1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBY69UzKWz2yNNRaEMDbNlhJux4dC2K_aX9DlbmsUYVg3029Mfhnw2w0MppDP7UJ1Fp5Z1DzWZR2CaVhH02qcwoXMytaMNPJXT-ZDntL3DHpcsmTlXpqwAkYJLybeloloMHvLX57Na7uSE/s1600/dynLayer1.png" /></a></div>
<br />
<br />
Poiché desideriamo aggiungere un layer dinamicamente clicchiamo su <strong>Manage... </strong>e registriamo uno o più geodatabase che contengono i dati che vogliamo utilizzare on the fly. Potremo caricare layer, table ad esempio per fare join.<br />
Quando indichiamo un geodatabase dobbiamo indicare un identificato univoco per quel workspace che sarà utilizzato dall'applicazione per aggiungere i dati. Possiamo indicare una cartella contenente raster o shapefile, un file geodatabase o un enterprise geodatabase. In questo ultimo caso abbiamo anche la possibilità di bloccare la versione utilizzata dall'utente.<br />
<br />
Selezioniamo un file geodatabase. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG6aHXsq-WM1unAt3ZULCwghUyWiULxcGtjQWXFiNaX7VVES9XLZZhkQ5qtrN5QBzYrddZxHRsJ_j9dv28JbIhBGV7ty3piigIpR-xUqX_LVFRT7Ebnz6EGDoueOpd6ELGqt1e9OYVoUnQ/s1600/dynlayer2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG6aHXsq-WM1unAt3ZULCwghUyWiULxcGtjQWXFiNaX7VVES9XLZZhkQ5qtrN5QBzYrddZxHRsJ_j9dv28JbIhBGV7ty3piigIpR-xUqX_LVFRT7Ebnz6EGDoueOpd6ELGqt1e9OYVoUnQ/s1600/dynlayer2.png" /></a></div>
<br />
In questo caso è lo stesso utilizzato dal servizio.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh70s3vp7VF_1U2O-QL4KY_e8t-6svSjN7txc5oH0oX3WOf8hXvglv5M2nhKlHYTcKF-ozv4N8r4dVhoUT8raG9PFjgJ1DMYBUBqFAN7HDRBTqJiEYrctZlGIhkd6VXr6nmZ0ggB1OxehQD/s1600/dynlayer3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh70s3vp7VF_1U2O-QL4KY_e8t-6svSjN7txc5oH0oX3WOf8hXvglv5M2nhKlHYTcKF-ozv4N8r4dVhoUT8raG9PFjgJ1DMYBUBqFAN7HDRBTqJiEYrctZlGIhkd6VXr6nmZ0ggB1OxehQD/s1600/dynlayer3.png" /></a></div>
<br />
Occorre ricordarsi che anche i workspace aggiunti per i dynamic layer devo essere registrati e l'utente ArcGIS Server deve avere almeno i privilegi di lettura per il workspace contenente i dati da caricare nel servizio.<br />
<br />
Con i web client Esri possiamo aggiungere dinamicamente il nostro layer. Ad esempio con le API javascript (analogamente possiamo utilizzare le classi relative anche agli altri web client Esri) creiamo un datasource con <a href="https://developers.arcgis.com/en/javascript/jsapi/tabledatasource.html" target="_blank">TableDataSource</a> e lo associamo ad un <a href="https://developers.arcgis.com/en/javascript/jsapi/layerdatasource.html" target="_blank">LayerDataSource</a> per poi utilizzarlo come source in un feature layer:<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: darkgreen;"> //define the layer's data source from a table</span>
<span style="color: blue;">var</span> dataSource = <span style="color: blue;">new</span> esri.layers.TableDataSource();
dataSource.workspaceId = <span style="color: maroon;">"My Workspace ID"</span>;
dataSource.dataSourceName = <span style="color: maroon;">"Cities"</span>;
<span style="color: blue;">var</span> layerSource = <span style="color: blue;">new</span> esri.layers.LayerDataSource();
layerSource.dataSource = dataSource;
<span style="color: darkgreen;">//create a new feature layer based on the table data source </span>
<span style="color: blue;">var</span> featureLayer = <span style="color: blue;">new</span> esri.layers.FeatureLayer(<span style="color: maroon;">'http://myserver:6080/arcgis/rest/services/Demo/USA/MapServer/dynamicLayer'</span>, {
mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
outFields: [<span style="color: maroon;">"*"</span>],
infoTemplate: infoTemplate,
source: layerSource
});</pre>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<br />
E qui possiamo vedere l'esempio completo:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;"><!</span><span style="color: maroon;">DOCTYPE</span> <span style="color: red;">html</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">html</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">head</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">title</span><span style="color: blue;">></span>Dynamic Layer<span style="color: blue;"></</span><span style="color: maroon;">title</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">meta</span> <span style="color: red;">http-equiv</span><span style="color: blue;">=</span><span style="color: blue;">"Content-Type"</span> <span style="color: red;">content</span><span style="color: blue;">=</span><span style="color: blue;">"text/html; charset=utf-8"</span> <span style="color: blue;">/></span>
<span style="color: blue;"><</span><span style="color: maroon;">meta</span> <span style="color: red;">http-equiv</span><span style="color: blue;">=</span><span style="color: blue;">"X-UA-Compatible"</span> <span style="color: red;">content</span><span style="color: blue;">=</span><span style="color: blue;">"IE=7, IE=9, IE=10"</span> <span style="color: blue;">/></span>
<span style="color: blue;"><</span><span style="color: maroon;">link</span> <span style="color: red;">rel</span><span style="color: blue;">=</span><span style="color: blue;">"stylesheet"</span> <span style="color: red;">href</span><span style="color: blue;">=</span><span style="color: blue;">"http://serverapi.arcgisonline.com/jsapi/arcgis/3.5/js/dojo/dijit/themes/claro/claro.css"</span> <span style="color: blue;">/></span>
<span style="color: blue;"><</span><span style="color: maroon;">link</span> <span style="color: red;">rel</span><span style="color: blue;">=</span><span style="color: blue;">"stylesheet"</span> <span style="color: red;">href</span><span style="color: blue;">=</span><span style="color: blue;">"http://serverapi.arcgisonline.com/jsapi/arcgis/3.5/js/esri/css/esri.css"</span> <span style="color: blue;">/></span>
<span style="color: blue;"><</span><span style="color: maroon;">style</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"text/css"</span><span style="color: blue;">></span>
<span style="color: maroon;">html</span>, <span style="color: maroon;">body</span>, <span style="color: maroon;">#mapDiv</span>, <span style="color: maroon;">.map.container</span>
{
<span style="color: red;">padding</span>: <span style="color: blue;">0</span>;
<span style="color: red;">margin</span>: <span style="color: blue;">0</span>;
<span style="color: red;">height</span>: <span style="color: blue;">100%</span>;
}
<span style="color: blue;"></</span><span style="color: maroon;">style</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">script</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"text/javascript"</span><span style="color: blue;">></span> dojoConfig = { parseOnLoad: <span style="color: blue;">true</span> };<span style="color: blue;"></</span><span style="color: maroon;">script</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">script</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"text/javascript"</span> <span style="color: red;">src</span><span style="color: blue;">=</span><span style="color: blue;">"http://serverapi.arcgisonline.com/jsapi/arcgis/3.5/"</span><span style="color: blue;">></</span><span style="color: maroon;">script</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">script</span> <span style="color: red;">type</span><span style="color: blue;">=</span><span style="color: blue;">"text/javascript"</span><span style="color: blue;">></span>
dojo.require(<span style="color: maroon;">"esri.map"</span>);
dojo.require(<span style="color: maroon;">"esri.layers.FeatureLayer"</span>);
<span style="color: blue;">var</span> map;
<span style="color: blue;">function</span> init() {
esri.config.defaults.geometryService = <span style="color: blue;">new</span> esri.tasks.GeometryService(<span style="color: maroon;">"http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer"</span>);
map = <span style="color: blue;">new</span> esri.Map(<span style="color: maroon;">"mapDiv"</span>, {
basemap: <span style="color: maroon;">"satellite"</span>,
center: [0, 0],
zoom: 2
});
map.on(<span style="color: maroon;">"load"</span>, initOperationalLayer);
}
<span style="color: blue;">function</span> initOperationalLayer() {
<span style="color: blue;">var</span> content = <span style="color: maroon;">"<b>Name</b>: ${AREANAME}"</span> + <span style="color: maroon;">"<br /><b>Pop</b>: ${POP2000}"</span>;
<span style="color: blue;">var</span> infoTemplate = <span style="color: blue;">new</span> esri.InfoTemplate(<span style="color: maroon;">"Dynamic Layer"</span>, content);
<span style="color: darkgreen;">//define the layer's data source from a table</span>
<span style="color: blue;">var</span> dataSource = <span style="color: blue;">new</span> esri.layers.TableDataSource();
dataSource.workspaceId = <span style="color: maroon;">"My Workspace ID"</span>;
dataSource.dataSourceName = <span style="color: maroon;">"Cities"</span>;
<span style="color: blue;">var</span> layerSource = <span style="color: blue;">new</span> esri.layers.LayerDataSource();
layerSource.dataSource = dataSource;
<span style="color: darkgreen;">//create a new feature layer based on the table data source </span>
<span style="color: blue;">var</span> featureLayer = <span style="color: blue;">new</span> esri.layers.FeatureLayer(<span style="color: maroon;">'http://myserver:6080/arcgis/rest/services/Demo/USA/MapServer/dynamicLayer'</span>, {
mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
outFields: [<span style="color: maroon;">"*"</span>],
infoTemplate: infoTemplate,
source: layerSource
});
featureLayer.on(<span style="color: maroon;">"load"</span>, <span style="color: blue;">function</span> (evt) {
<span style="color: darkgreen;">//project the extent if the map's spatial reference is different that the layer's extent.</span>
<span style="color: blue;">var</span> gs = esri.config.defaults.geometryService;
<span style="color: blue;">var</span> extent = evt.layer.fullExtent;
<span style="color: blue;">if</span> (extent.spatialReference.wkid === map.spatialReference.wkid) {
map.setExtent(extent);
} <span style="color: blue;">else</span> {
gs.project([extent], map.spatialReference).then(<span style="color: blue;">function</span> (results) {
map.setExtent(results[0]);
});
}
});
<span style="color: blue;">var</span> renderer = <span style="color: blue;">new</span> esri.renderer.SimpleRenderer(
<span style="color: blue;">new</span> esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_SQUARE, 10,
<span style="color: blue;">new</span> esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID,
<span style="color: blue;">new</span> dojo.Color([255, 0, 0]), 1),
<span style="color: blue;">new</span> dojo.Color([0, 255, 0, 0.25])));
featureLayer.setRenderer(renderer);
map.addLayer(featureLayer);
map.infoWindow.resize(150, 105);
}
dojo.ready(init);
<span style="color: blue;"></</span><span style="color: maroon;">script</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">head</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">body</span> <span style="color: red;">class</span><span style="color: blue;">=</span><span style="color: blue;">"claro"</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">div</span> <span style="color: red;">id</span><span style="color: blue;">=</span><span style="color: blue;">"mapDiv"</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">div</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">body</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">html</span><span style="color: blue;">></span>
</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEWYMU2hWG4FDBj-X9HTRI0JgvlY1i7MnLlVqZX7uIn8AympdWksL7uirKLglilSVeYoCSlEaySDhQIbC4y5IsvRyCG3qpjl4qNX7RntlQybpz27kAhJY6RRaNZA1WQAK0Te-zQf2euAuK/s1600/dyn-layer4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEWYMU2hWG4FDBj-X9HTRI0JgvlY1i7MnLlVqZX7uIn8AympdWksL7uirKLglilSVeYoCSlEaySDhQIbC4y5IsvRyCG3qpjl4qNX7RntlQybpz27kAhJY6RRaNZA1WQAK0Te-zQf2euAuK/s1600/dyn-layer4.png" /></a></div>
<br />
<br />
Qui abbiamo visto un semplice esempio ma potete far caricare dall'utente i propri layer utilizzando ad esempio un servizio di geoprocessing che carica il dato in uno dei workspace registrati nel pool dei workspace del servizio con un nome univoco del layer (ad esempio facendo generare al geoprocessing un <a href="http://it.wikipedia.org/wiki/GUID" target="_blank">GUID</a>) e restituendo al client il nome univoco del layer così che lo possa caricare con il codice visto precedentemente.<br />
<br />
Possiamo anche caricare tabelle e fare join on the fly. Per maggiori dettagli vedere la classe <a href="https://developers.arcgis.com/en/javascript/jsapi/joindatasource.html" target="_blank">JoinDataSource</a><br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902007 9.255947099999957620.068166199999997 -32.052646900000042 71.1122352 50.564541099999957tag:blogger.com,1999:blog-8323071861123024882.post-68776631373148586202013-05-31T22:49:00.000+02:002013-07-31T20:05:01.611+02:00Time EvaluatorL'extension <a href="http://www.esri.com/software/arcgis/extensions/networkanalyst" target="_blank">Network Analyst</a> disponibile sia in ambiente Desktop che Server permette la gestione e le analisi spaziali basate su reti come routing, fleet routing, travel directions, closest facility, service area, e location-allocation.<br />
Se però volessimo gestire la schedulazione dell'orario dei bus nella nostra analisi - in modo che, se una route arriva ad uno stop del bus prima del prossimo orario schedulato di partenza, essa debba attendere - occorrerebbe sviluppare un custom evaluator. Infatti, per gestire la schedulazione dell'orario dei bus, non è prevista una soluzione out-of-box ma lo sarà nelle successive release.<br />
Fortunatamente tuttavia è disponibile, sin dalla versione 10.0, l'interfaccia <a href="http://help.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelp/index.html#/QueryValueAtTime_Method/0025000008pm000000/" target="_blank">ITimeAwareEvaluator</a> che ci permette - sviluppando un custom time-aware network attribute evaluator - di gestire anche questa problematica in modo molto semplice. Chiaramente potremo poi esporre la stessa funzionalità lato server tramite ArcGIS Server registrando opportunamente la dll.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo_LNgdcbyEDxi1P43EtfXsrNGMQmvWb24_P-J9xZH2VnSFveu59F7_fR-fyYXTN_-8dcTdJOR5i-a_Bw9FbTJEIIaKYJx_rsozdT65e0fqq8Pk97iPTtlZWA1MvBlHutmTDwVaoQmkDYu/s1600/Evaluator1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo_LNgdcbyEDxi1P43EtfXsrNGMQmvWb24_P-J9xZH2VnSFveu59F7_fR-fyYXTN_-8dcTdJOR5i-a_Bw9FbTJEIIaKYJx_rsozdT65e0fqq8Pk97iPTtlZWA1MvBlHutmTDwVaoQmkDYu/s640/Evaluator1.png" width="435" /></a></div>
<br />
Creiamo un progetto in Visual Studio per creare una class library (.dll).<br />
La nostra classe dovrà implementare le seguenti interfacce <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/00250000058t000000.htm" target="_blank">INetworkEvaluator2</a>, <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/00250000058z000000.htm" target="_blank">INetworkEvaluatorSetup</a> e, come già detto, <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000008p8000000.htm" target="_blank">ITimeAwareEvaluator</a>.<br />
<br />
Se volessimo impostare anche delle proprietà, tramite ArcCatalog, del custom evaluator potremmo anche creare una classe che implementa l'interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0015/00150000009v000000.htm" target="_blank">IEvaluatorEditor</a> e crearci la nostra interfaccia utente ad esempio tramite una Windows Form. L'associazione con l'evaluator avviene impostando il CLSID dell'evaluator nella proprietà <strong>EvaluatorCLSID</strong> e tramite la proprietà <strong>EditEvaluators</strong>, utilizzata da ArcCatalog per impostare un riferimento ai suoi object EditEvaluator su ogni EvaluatorEditor registrato e consente così di accedere allo stato corrente della finestra di dialogo degli Evaluator e listare quelli correnti e selezionati per poi leggere ed impostare la proprietà <strong>Data </strong>da utilizzare nell'evaluator.<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: green;">// -----------------------------------------------------------------------</span>
<span style="color: green;">// <copyright file="DepartureTimeEvaluatorEditor.cs" company="Studio A&T s.r.l."></span>
<span style="color: green;">// Copyright (c) Studio A&T s.r.l. All rights reserved.</span>
<span style="color: green;">// </copyright></span>
<span style="color: green;">// <author>Nicogis</author></span>
<span style="color: green;">// -----------------------------------------------------------------------</span>
<span style="color: blue;">namespace</span> Studioat.ArcGIS.DepartureTimeEvaluator
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Collections.Generic;
<span style="color: blue;">using</span> System.Runtime.InteropServices;
<span style="color: blue;">using</span> ESRI.ArcGIS.ADF.CATIDs;
<span style="color: blue;">using</span> ESRI.ArcGIS.CatalogUI;
<span style="color: blue;">using</span> ESRI.ArcGIS.esriSystem;
<span style="color: blue;">using</span> ESRI.ArcGIS.Geodatabase;
[<span style="color: #2b91af;">ClassInterface</span>(<span style="color: #2b91af;">ClassInterfaceType</span>.None)]
[<span style="color: #2b91af;">Guid</span>(<span style="color: #a31515;">"7409A80D-13BB-46EB-8658-B1757CEB0CCA"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">DepartureTimeEvaluatorEditor</span> : <span style="color: #2b91af;">IEvaluatorEditor</span>
{
<span style="color: blue;"> #region</span> Component Category Registration
[<span style="color: #2b91af;">ComRegisterFunction</span>()]
[<span style="color: #2b91af;">ComVisible</span>(<span style="color: blue;">false</span>)]
<span style="color: blue;">static</span> <span style="color: blue;">void</span> RegisterFunction(<span style="color: #2b91af;">Type</span> registerType)
{
<span style="color: blue;">string</span> regKey = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}"</span>, registerType.GUID);
<span style="color: #2b91af;">NetworkEvaluatorEditor</span>.Register(regKey);
}
[<span style="color: #2b91af;">ComUnregisterFunction</span>()]
[<span style="color: #2b91af;">ComVisible</span>(<span style="color: blue;">false</span>)]
<span style="color: blue;">static</span> <span style="color: blue;">void</span> UnregisterFunction(<span style="color: #2b91af;">Type</span> registerType)
{
<span style="color: blue;">string</span> regKey = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}"</span>, registerType.GUID);
<span style="color: #2b91af;">NetworkEvaluatorEditor</span>.Unregister(regKey);
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> IEvaluatorEditor Members
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> ContextSupportsEditDescriptors
{
<span style="color: green;">// The descriptor text is the single line of text in the Evaluators dialog that appears under the Value column.</span>
<span style="color: green;">// This property indicates whether the descriptor text can be directly edited in the dialog by the user.</span>
<span style="color: green;">// Since this evaluator editor does not make use of descriptors, it returns false</span>
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: blue;">false</span>; }
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> EditDescriptors(<span style="color: blue;">string</span> value)
{
<span style="color: green;">// This evaluator editor does not make use of descriptors.</span>
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> ContextSupportsEditProperties
{
<span style="color: green;">// This property indicates whether the ArcCatalog user is able to bring up a dialog by </span>
<span style="color: green;">// clicking the Properties button (or pressing F12) in order to specify settings for the evaluator.</span>
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: blue;">true</span>; }
}
<span style="color: blue;">private</span> <span style="color: #2b91af;">IEditEvaluators</span> m_EditEvaluators;
<span style="color: blue;">public</span> <span style="color: #2b91af;">IEditEvaluators</span> EditEvaluators
{
<span style="color: green;">// This property is used by ArcCatalog to set a reference to its EditEvaluators object </span>
<span style="color: green;">// on each registered EvaluatorEditor. This allows each EvaluatorEditor to access the </span>
<span style="color: green;">// current state of ArcCatalog's Evaluators dialog, such as how many evaluators are listed </span>
<span style="color: green;">// and which evaluators are currently selected.</span>
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> m_EditEvaluators; }
<span style="color: blue;">set</span> { m_EditEvaluators = <span style="color: blue;">value</span>; }
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> EditProperties(<span style="color: blue;">int</span> parentWindow)
{
<span style="color: green;">// Get an array of the currently selected evaluators to pass to the properties form.</span>
<span style="color: blue;">var</span> evaluators = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">INetworkEvaluator</span>>();
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < m_EditEvaluators.Count; i++)
{
<span style="color: blue;">if</span> (m_EditEvaluators.get_IsSelected(i))
evaluators.Add(m_EditEvaluators.get_EditEvaluator(i));
}
<span style="color: #2b91af;">PropertiesDialog</span> form = <span style="color: blue;">new</span> <span style="color: #2b91af;">PropertiesDialog</span>(evaluators);
form.ShowDialog();
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">public</span> <span style="color: #2b91af;">UID</span> EvaluatorCLSID
{
<span style="color: blue;">get</span>
{
<span style="color: green;">// This property returns the GUID of this EvaluatorEditor's associated INetworkEvaluator.</span>
<span style="color: #2b91af;">UID</span> uid = <span style="color: blue;">new</span> <span style="color: #2b91af;">UIDClass</span>();
uid.Value = <span style="color: #a31515;">"{13C81137-7DE4-40B4-9A73-71271CEE44BE}"</span>;
<span style="color: blue;">return</span> uid;
}
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> SetDefaultProperties(<span style="color: blue;">int</span> index)
{
<span style="color: green;">// This method is called when the ArcCatalog user selects this evaluator </span>
<span style="color: green;">// under the Type column of the Evaluators dialog. This method can be used to </span>
<span style="color: green;">// initialize any dialogs that the evaluator editor uses.</span>
}
<span style="color: blue;">public</span> <span style="color: blue;">int</span> ValueChoice
{
<span style="color: green;">// This evaluator editor does not support value choices.</span>
<span style="color: blue;">set</span> { }
}
<span style="color: blue;">public</span> <span style="color: blue;">int</span> ValueChoiceCount
{
<span style="color: green;">// This evaluator editor has no value choices.</span>
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> 0; }
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> get_Descriptor(<span style="color: blue;">int</span> index)
{
<span style="color: green;">// This evaluator editor does not make use of descriptors.</span>
<span style="color: blue;">return</span> <span style="color: blue;">string</span>.Empty;
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> get_FullDescription(<span style="color: blue;">int</span> index)
{
<span style="color: green;">// This property is the text representation of all of the settings made on this evaluator.</span>
<span style="color: green;">// This evaluator editor does not make any settings changes, so it returns an empty string.</span>
<span style="color: blue;">return</span> <span style="color: blue;">string</span>.Empty;
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> get_ValueChoiceDescriptor(<span style="color: blue;">int</span> choice)
{
<span style="color: green;">// This evaluator editor does not make use of value choices.</span>
<span style="color: blue;">return</span> <span style="color: blue;">string</span>.Empty;
}
<span style="color: blue;"> #endregion</span>
}
}</pre>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
Mentre la form imposta e legge la property <strong>Data</strong> dell'evaluator:<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">namespace</span> Studioat.ArcGIS.DepartureTimeEvaluator
{
<span style="color: blue;">public</span> <span style="color: blue;">partial</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">PropertiesDialog</span> : <span style="color: #2b91af;">Form</span>
{
<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">INetworkEvaluator</span>> m_evaluators;
<span style="color: blue;">public</span> PropertiesDialog(<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">INetworkEvaluator</span>> evaluators)
{
m_evaluators = evaluators;
InitializeComponent();
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> evaluator <span style="color: blue;">in</span> m_evaluators)
{
<span style="color: blue;">var</span> evaluatorSetup = evaluator <span style="color: blue;">as</span> <span style="color: #2b91af;">INetworkEvaluatorSetup</span>;
<span style="color: #2b91af;">IPropertySet</span> propSet = evaluatorSetup.Data;
<span style="color: blue;">if</span> (propSet != <span style="color: blue;">null</span>)
{
txtFilePath.Text = propSet.GetProperty(<span style="color: #2b91af;">DepartureTimeEvaluator</span>.PROPNAME_SCHEDULE_FILEGDB_PATH).ToString();
}
}
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> btnCancel_Click(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: blue;">this</span>.Close();
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> btnOK_Click(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: blue;">string</span> scheduleFilePath = txtFilePath.Text;
<span style="color: blue;">if</span> (!<span style="color: #2b91af;">File</span>.Exists(scheduleFilePath))
{
<span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Schedule file gdb does not exist"</span>);
<span style="color: blue;">return</span>;
}
<span style="color: blue;">foreach</span> (<span style="color: blue;">var</span> evaluator <span style="color: blue;">in</span> m_evaluators)
{
<span style="color: blue;">var</span> evaluatorSetup = evaluator <span style="color: blue;">as</span> <span style="color: #2b91af;">INetworkEvaluatorSetup</span>;
<span style="color: #2b91af;">IPropertySet</span> propSet = evaluatorSetup.Data;
<span style="color: blue;">if</span> (propSet == <span style="color: blue;">null</span>)
propSet = <span style="color: blue;">new</span> <span style="color: #2b91af;">PropertySetClass</span>();
propSet.SetProperty(<span style="color: #2b91af;">DepartureTimeEvaluator</span>.PROPNAME_SCHEDULE_FILEGDB_PATH, scheduleFilePath);
evaluatorSetup.Data = propSet;
}
<span style="color: blue;">this</span>.Close();
}
}
}</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEeBCfmzB24WDKNDdz-FDDDZKH3av2S-tgPVn-ZffnPgoZVHY041HQlZvZs2qnw_URFMnO8CxOdS53e-aFYbqf1RczgEEC5opqiYD_Kw8ouUSuLLzurH2BDhO6FOq07XiPQVi2UntRJ299/s1600/evaluator10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="586" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEeBCfmzB24WDKNDdz-FDDDZKH3av2S-tgPVn-ZffnPgoZVHY041HQlZvZs2qnw_URFMnO8CxOdS53e-aFYbqf1RczgEEC5opqiYD_Kw8ouUSuLLzurH2BDhO6FOq07XiPQVi2UntRJ299/s640/evaluator10.png" width="640" /></a></div>
<br />
<br />
<br />
In questo caso specifico una proprietà per questo tipo di evaluator è la tabella che contiene gli orari dei singoli tratti delle linee bus, relazionata (uno a molti) con i singoli tratti delle linee bus.<br />
Possiamo dare un nome ben preciso alla tabella e decidere che si deve trovare nello stesso workspace del nostro network dataset e così non abbiamo bisogno di proprietà particolari da far selezionare all'utente o dare la possibilità all'utente di selezionare una tabella, con determinate caratteristiche, in un qualsiasi workspace e così abiliteremo l'editor come visto sopra (proprietà <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0015/00150000009z000000.htm" target="_blank">ContextSupportsEditProperties</a> in <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0015/00150000009v000000.htm" target="_blank">IEvaluatorEditor</a>).<br />
<br />
<br />
<br />
<br />
Vediamo nel dettaglio l'implementazione delle interfacce <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/00250000058t000000.htm" target="_blank">INetworkEvaluator2</a> e <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/00250000058z000000.htm" target="_blank">INetworkEvaluatorSetup</a>:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> [<span style="color: #2b91af;">ClassInterface</span>(<span style="color: #2b91af;">ClassInterfaceType</span>.None)]
[<span style="color: #2b91af;">Guid</span>(<span style="color: #a31515;">"13C81137-7DE4-40B4-9A73-71271CEE44BE"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">DepartureTimeEvaluator</span> : <span style="color: #2b91af;">INetworkEvaluator2</span>, <span style="color: #2b91af;">INetworkEvaluatorSetup</span>, <span style="color: #2b91af;">ITimeAwareEvaluator</span>
{
<span style="color: blue;"> #region</span> Member Variables
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">readonly</span> <span style="color: blue;">string</span> tableStopToStopTime = <span style="color: #a31515;">"StopToStopTime"</span>;
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">readonly</span> <span style="color: #2b91af;">TimeSpan</span> midnightTransit = <span style="color: blue;">new</span> <span style="color: #2b91af;">TimeSpan</span>(24, 0, 0);
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">readonly</span> <span style="color: #2b91af;">TimeSpan</span> midnight = <span style="color: blue;">new</span> <span style="color: #2b91af;">TimeSpan</span>(0, 0, 0);
<span style="color: blue;">private</span> <span style="color: #2b91af;">IFeatureWorkspace</span> featureWorkspace = <span style="color: blue;">null</span>;
<span style="color: blue;">private</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">StopToStopTime</span>> stopToStopTime = <span style="color: blue;">null</span>;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">int</span>, <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">StopToStopTime</span>>> track = <span style="color: blue;">null</span>;
<span style="color: blue;">private</span> <span style="color: blue;">int</span>? idEdgeStart = <span style="color: blue;">null</span>;
<span style="color: blue;">private</span> <span style="color: #2b91af;">TimeSpan</span> timeSpanStart = <span style="color: #2b91af;">TimeSpan</span>.Zero;
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> INetworkEvaluator Members
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> CacheAttribute
{
<span style="color: green;">// CacheAttribute returns whether or not we want the network dataset to cache our evaluated attribute </span>
<span style="color: green;">// values during the network dataset build. Since this is a dynamic evaluator, we will return false, </span>
<span style="color: green;">// so that our attribute values are dynamically queried at runtime.</span>
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: blue;">false</span>; }
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> DisplayName
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: #a31515;">"BusTimeEvaluator"</span>; }
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Name
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: #a31515;">"Studioat.ArcGIS.DepartureTimeEvaluator.DepartureTimeEvaluator"</span>; }
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> INetworkEvaluatorSetup Members
<span style="color: blue;">public</span> <span style="color: #2b91af;">UID</span> CLSID
{
<span style="color: blue;">get</span>
{
<span style="color: green;">// Create and return the GUID for this custom evaluator</span>
<span style="color: #2b91af;">UID</span> uid = <span style="color: blue;">new</span> <span style="color: #2b91af;">UIDClass</span>();
uid.Value = <span style="color: #a31515;">"{13C81137-7DE4-40B4-9A73-71271CEE44BE}"</span>;
<span style="color: blue;">return</span> uid;
}
}
<span style="color: blue;">public</span> <span style="color: #2b91af;">IPropertySet</span> Data
{
<span style="color: green;">// The Data property is intended to make use of property sets to get/set the custom </span>
<span style="color: green;">// evaluator's properties using only one call to the evaluator object.</span>
<span style="color: blue;">get</span>;
<span style="color: blue;">set</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> DataHasEdits
{
<span style="color: green;">// Since this custom evaluator does not make any data edits, return false.</span>
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: blue;">false</span>; }
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Initialize(<span style="color: #2b91af;">INetworkDataset</span> networkDataset, <span style="color: #2b91af;">IDENetworkDataset</span> dataElement, <span style="color: #2b91af;">INetworkSource</span> source, <span style="color: #2b91af;">IEvaluatedNetworkAttribute</span> attribute)
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">IDataset</span> dataset = networkDataset <span style="color: blue;">as</span> <span style="color: #2b91af;">IDataset</span>;
<span style="color: blue;">this</span>.featureWorkspace = dataset.Workspace <span style="color: blue;">as</span> <span style="color: #2b91af;">IFeatureWorkspace</span>;
<span style="color: green;">//ESRI.ArcGIS.Geodatabase.INetworkSource netSource = networkDataset.get_SourceByID(this.sourceID);</span>
<span style="color: green;">//// Get the network source as a feature class.</span>
<span style="color: green;">//IFeatureClassContainer featureClassContainer = networkDataset as IFeatureClassContainer;</span>
<span style="color: green;">//this.featureClassStop = featureClassContainer.get_ClassByName(netSource.Name);</span>
CacheSchedules();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Evaluator initialization failure for "</span> + DisplayName + <span style="color: #a31515;">". Error message: "</span> + e.Message);
}
}
<span style="color: blue;">public</span> <span style="color: blue;">object</span> QueryValue(<span style="color: #2b91af;">INetworkElement</span> element, <span style="color: #2b91af;">IRow</span> row)
{
<span style="color: green;">// If this evaluator is queried without specifying a time, then the element has no added costs.</span>
<span style="color: blue;">return</span> 0;
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> SupportsDefault(<span style="color: #2b91af;">esriNetworkElementType</span> elementType, <span style="color: #2b91af;">IEvaluatedNetworkAttribute</span> attribute)
{
<span style="color: green;">// This custom evaluator can not be used for assigning default attribute values.</span>
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> SupportsSource(<span style="color: #2b91af;">INetworkSource</span> source, <span style="color: #2b91af;">IEvaluatedNetworkAttribute</span> attribute)
{
<span style="color: green;">// This custom evaluator supports added costs only for turns.</span>
<span style="color: blue;">bool</span> isEdgeSource = (source.ElementType == <span style="color: #2b91af;">esriNetworkElementType</span>.esriNETEdge);
<span style="color: blue;">bool</span> isCostAttribute = (attribute.UsageType == <span style="color: #2b91af;">esriNetworkAttributeUsageType</span>.esriNAUTCost);
<span style="color: blue;">return</span> (isEdgeSource && isCostAttribute);
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> ValidateDefault(<span style="color: #2b91af;">esriNetworkElementType</span> elementType, <span style="color: #2b91af;">IEvaluatedNetworkAttribute</span> attribute, <span style="color: blue;">ref</span> <span style="color: blue;">int</span> errorCode, <span style="color: blue;">ref</span> <span style="color: blue;">string</span> errorDescription, <span style="color: blue;">ref</span> <span style="color: blue;">string</span> errorAppendInfo)
{
<span style="color: blue;">if</span> (SupportsDefault(elementType, attribute))
{
errorCode = 0;
errorDescription = errorAppendInfo = <span style="color: blue;">string</span>.Empty;
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
<span style="color: blue;">else</span>
{
errorCode = -1;
errorDescription = errorAppendInfo = <span style="color: blue;">string</span>.Empty;
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> ValidateSource(<span style="color: #2b91af;">IDatasetContainer2</span> datasetContainer, <span style="color: #2b91af;">INetworkSource</span> networkSource, <span style="color: #2b91af;">IEvaluatedNetworkAttribute</span> attribute, <span style="color: blue;">ref</span> <span style="color: blue;">int</span> errorCode, <span style="color: blue;">ref</span> <span style="color: blue;">string</span> errorDescription, <span style="color: blue;">ref</span> <span style="color: blue;">string</span> errorAppendInfo)
{
<span style="color: blue;">if</span> (SupportsSource(networkSource, attribute))
{
errorCode = 0;
errorDescription = errorAppendInfo = <span style="color: blue;">string</span>.Empty;
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
<span style="color: blue;">else</span>
{
errorCode = -1;
errorDescription = errorAppendInfo = <span style="color: blue;">string</span>.Empty;
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> INetworkEvaluator2 Members
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Refresh()
{
<span style="color: green;">// Refresh is called for each evaluator on each solve.</span>
<span style="color: blue;">try</span>
{
<span style="color: blue;">this</span>.track = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">int</span>, <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">StopToStopTime</span>>>();
<span style="color: blue;">this</span>.idEdgeStart = <span style="color: blue;">null</span>;
<span style="color: blue;">this</span>.CacheSchedules();
LogMessage(<span style="color: #a31515;">"Solve called (Refresh)"</span>);
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Evaluator refresh failure for "</span> + DisplayName + <span style="color: #a31515;">". Error message: "</span> + e.Message);
}
}
<span style="color: blue;">public</span> <span style="color: #2b91af;">IStringArray</span> RequiredFieldNames
{
<span style="color: green;">// This custom evaluator does not require any field names.</span>
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: blue;">null</span>; }
}
<span style="color: blue;"> #endregion</span></pre>
<br />
Per la proprietà <strong>CacheAttribute</strong> restituiamo false perché in questo caso l'evaluator è dinamico nel senso che l'attributo è valutato a run time e quando viene fatto un build della network non occorre memorizzare i valori degli attributi dell'evaluator.<br />
Il <strong>DisplayName</strong> è il nome dell'evaluator che viene visto in ArcCatalog mentre <strong>Name</strong> è il nome univoco dell'evaluator.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeA8Z1CsefrXfuYmZ9CxBkpNZvJNDlsu07SfioNeYEXdJpw-3Zc9htnoI5TtU-SQqdPiyM4_4COZuzth50kacuqdXjQwo-ARWGG1Hj0EpVRghwceVYBitS11Fa3St5dGaIQ1CUd2BFbZ9g/s1600/evaluator2n.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="598" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeA8Z1CsefrXfuYmZ9CxBkpNZvJNDlsu07SfioNeYEXdJpw-3Zc9htnoI5TtU-SQqdPiyM4_4COZuzth50kacuqdXjQwo-ARWGG1Hj0EpVRghwceVYBitS11Fa3St5dGaIQ1CUd2BFbZ9g/s640/evaluator2n.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"> </pre>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<strong>CLSID </strong>è la GUID del nostro custom evaluator.<br />
<br />
<strong>Data </strong>è il propertySet che memorizza eventuali impostazione del nostro custom evaluator, che possono essere impostare utilizzando <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0015/00150000009v000000.htm" target="_blank">IEvaluatorEditor</a>.<br />
<br />
<strong>DataHasEdits</strong> per notificare se sono state fatte modifiche a <strong>Data</strong> e quindi per poter reinizializzare l'evaluator.<br />
<br />
<strong>Initialize </strong>metodo che inizializza l'evaluator ad essere utilizzato per l'interrogazione degli attributi. Nel nostro caso il metodo viene eseguito sulla prima chiamata nella sessione che richiede che l'evaluator determini il valore dell'attributo.<br />
<br />
<strong>QueryValue </strong>metodo che non viene utilizzato. Se l'evaluator è interrogato senza impostare lo Start Time per gli elementi non aggiungiamo costi e quindi impostiamo a 0.<br />
<br />
<strong>SupportDefault </strong>impostiamo a false così da non mostrare in ArcCatalog la possibilità di sceglierlo come evaluator di default<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGk3iHS94cPL9PjY0gF40MOSWXFp9LgF0pzNbgnkP6lmbARKqhGGB-V6u9Wfx3_CW5Rh2SYqPhx_aZWQSOjq_NaGkxcRAUfyhaK42TIiLdTIf8yiTo7EE0tcL12h7-O5Y9RHxAxb28ruBK/s1600/evaluator3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGk3iHS94cPL9PjY0gF40MOSWXFp9LgF0pzNbgnkP6lmbARKqhGGB-V6u9Wfx3_CW5Rh2SYqPhx_aZWQSOjq_NaGkxcRAUfyhaK42TIiLdTIf8yiTo7EE0tcL12h7-O5Y9RHxAxb28ruBK/s640/evaluator3.png" width="640" /></a></div>
<br />
<strong>SupportSource </strong>se l'evaluator può essere utilizzato per assegnare valori degli attributi di date risorse. Nel nostro caso verifichiamo che sia un attributo di tipo costo ed applicato ad elementi di tipo edge.<br />
<br />
<strong>ValidateDefault</strong> e <strong>ValidateSource</strong> indica se l'evaluator è in uno stato valido per essere utilizzato come Default evaluator o evaluator per la data source e attributo della network.<br />
<br />
<strong>Refresh </strong>il metodo è chiamato ogni volta che eseguiamo un solve. Nel nostro caso potremmo rileggere (se serve) la schedulazione degli orari dei bus.<br />
<br />
<strong>RequiredFieldNames</strong> per minimizzare i dati restituiti dalla query è possibile impostare solo i campi che servono all'evaluator od impostare null se sono necessari tutti i campi. Ma nel nostro caso restituimo null perché l'evaluator non richiede campi dato che il metodo query non viene utilizzato.<br />
<br />
Ma il core della funzionalità è implementato dall'interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000008p8000000.htm" target="_blank">ITimeAwareEvaluator</a> con il metodo <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000008pm000000.htm" target="_blank">QueryValueAtTime</a> :<br />
<br />
Tramite <em>element </em>ci facciamo restituire l'objectId dell'elemento corrente interrogato e con questo filtriamo la tabella delle schedulazioni per farci restituire tutti gli orari di partenza dell'edge corrente. A questo punto selezioniamo l'orario più vicino e superiore a quello corrente (<em>queryTime</em>), ne calcoliamo la differenza (tempo di attesa) e sommiamo il tempo per percorrere il tratto corrente (orario di partenza - orario di arrivo):<br />
<br />
<div style="text-align: center;">
<strong>Impedance edge = wait time + edge time</strong></div>
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: blue;">#region</span> ITimeAwareEvaluator
<span style="color: blue;">public</span> <span style="color: blue;">object</span> QueryValueAtTime(<span style="color: #2b91af;">INetworkElement</span> element, <span style="color: #2b91af;">DateTime</span> queryTime, <span style="color: #2b91af;">esriNetworkTimeUsage</span> timeUsage)
{
<span style="color: green;">// Note that all query times are local times in the time zone of the network element.</span>
<span style="color: green;">// This element has added costs if its associated ObjectID is currently stored within </span>
<span style="color: green;">// the network source's hashtable. The added cost is equal to the amount of wait time </span>
<span style="color: green;">// from the query time to the next scheduled departure.</span>
<span style="color: blue;">int</span> oid = element.OID;
<span style="color: blue;">var</span> stopToStopTime = <span style="color: blue;">this</span>.stopToStopTime.Where(f => f.OIDStopToStop == oid).OrderBy(c => c.StartTime);
<span style="color: #2b91af;">TimeSpan</span> queryTimeOfDay = queryTime.TimeOfDay;
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.idEdgeStart.HasValue)
{
<span style="color: blue;">if</span> ((<span style="color: blue;">this</span>.idEdgeStart == oid) && (<span style="color: blue;">this</span>.timeSpanStart == queryTimeOfDay))
{
LogMessage(<span style="color: #a31515;">"----------------------------------Start Path ---------------------------------------------"</span>);
}
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">this</span>.idEdgeStart = oid;
<span style="color: blue;">this</span>.timeSpanStart = queryTimeOfDay;
LogMessage(<span style="color: #a31515;">"------------------------------------------------------------------------------------------"</span>);
LogMessage(<span style="color: #a31515;">"----------------------------------Start Path ---------------------------------------------"</span>);
}
LogMessage(<span style="color: #a31515;">"TimeOfDay: "</span> + queryTimeOfDay.ToString() + <span style="color: #a31515;">"queryTime:"</span> + queryTime.ToString());
LogMessage(<span style="color: #a31515;">"OID: "</span> + oid + <span style="color: #a31515;">" - SourceOID: "</span> + element.SourceID + <span style="color: #a31515;">" - TimeUsage:"</span> + ((<span style="color: blue;">int</span>)timeUsage == 1? <span style="color: #a31515;">"before"</span> : <span style="color: #a31515;">"after"</span>));
<span style="color: green;">//check if span multiple date and queryTimeOfDay is between midnight and max starttime next day</span>
<span style="color: blue;">if</span> (stopToStopTime.Where(t => t.StartTime >= midnightTransit).Count() > 0)
{
<span style="color: #2b91af;">TimeSpan</span> maxTimeNextDay = stopToStopTime.Where(t => t.StartTime >= midnightTransit).Max(k => k.StartTime);
<span style="color: blue;">if</span> ((maxTimeNextDay.Subtract(midnightTransit) >= queryTimeOfDay) && (queryTimeOfDay >= midnight))
{
queryTimeOfDay = queryTimeOfDay.Add(midnightTransit);
}
}
<span style="color: blue;">var</span> schedule = stopToStopTime.Where(t => t.StartTime >= queryTimeOfDay);
<span style="color: blue;">double</span> seconds;
<span style="color: #2b91af;">StopToStopTime</span> s;
<span style="color: blue;">if</span> (schedule.Count() == 0)
{
LogMessage(<span style="color: #a31515;">"schedulate next day"</span>);
s = stopToStopTime.First();
<span style="color: blue;">double</span> midnightWait = 0.0;
<span style="color: blue;">if</span> (queryTimeOfDay.Ticks != 0) <span style="color: green;">// it isn't midnight</span>
{
midnightWait = midnightTransit.Subtract(queryTimeOfDay).TotalSeconds;
}
seconds = midnightWait + s.StartTime.TotalSeconds + s.Seconds; <span style="color: green;">//(until midnight + from first start) wait time + edge time</span>
}
<span style="color: blue;">else</span>
{
s = schedule.First();
<span style="color: #2b91af;">TimeSpan</span> schedulateTime = s.StartTime;
seconds = schedulateTime.Subtract(queryTimeOfDay).TotalSeconds + s.Seconds; <span style="color: green;">//wait time + edge time </span>
}
LogMessage(<span style="color: #a31515;">"Seconds:"</span> + seconds);
LogMessage(<span style="color: #a31515;">"------------------------------------------------------------------------------------------"</span>);
<span style="color: blue;">return</span> seconds;
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;">private</span> <span style="color: blue;">void</span> CacheSchedules()
{
<span style="color: #2b91af;">ITable</span> tableStopToStopTime = <span style="color: blue;">this</span>.featureWorkspace.OpenTable(<span style="color: #2b91af;">DepartureTimeEvaluator</span>.tableStopToStopTime);
<span style="color: blue;">this</span>.stopToStopTime = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">StopToStopTime</span>>();
<span style="color: blue;">using</span> (<span style="color: #2b91af;">ComReleaser</span> comReleaser = <span style="color: blue;">new</span> <span style="color: #2b91af;">ComReleaser</span>())
{
<span style="color: #2b91af;">ICursor</span> cursor = tableStopToStopTime.Search(<span style="color: blue;">null</span>, <span style="color: blue;">true</span>);
<span style="color: blue;">int</span> idxFieldArrivalTime = tableStopToStopTime.FindField(<span style="color: #a31515;">"ArrivalTime"</span>);
<span style="color: blue;">int</span> idxFieldDepartureTime = tableStopToStopTime.FindField(<span style="color: #a31515;">"DepartureTime"</span>);
<span style="color: blue;">int</span> idxFieldOIDStopToStop = tableStopToStopTime.FindField(<span style="color: #a31515;">"OIDStopToStop"</span>);
comReleaser.ManageLifetime(cursor);
<span style="color: #2b91af;">IRow</span> row = cursor.NextRow();
<span style="color: blue;">while</span> (row != <span style="color: blue;">null</span>)
{
<span style="color: blue;">string</span>[] start = <span style="color: #2b91af;">Convert</span>.ToString(row.get_Value(idxFieldDepartureTime)).Split(<span style="color: blue;">new</span> <span style="color: blue;">char</span>[] { <span style="color: #a31515;">':'</span> });
<span style="color: #2b91af;">TimeSpan</span> departureTime = <span style="color: blue;">new</span> <span style="color: #2b91af;">TimeSpan</span>(<span style="color: #2b91af;">Convert</span>.ToInt32(start[0]), <span style="color: #2b91af;">Convert</span>.ToInt32(start[1]), <span style="color: #2b91af;">Convert</span>.ToInt32(start[2]));
<span style="color: blue;">string</span>[] end = <span style="color: #2b91af;">Convert</span>.ToString(row.get_Value(idxFieldArrivalTime)).Split(<span style="color: blue;">new</span> <span style="color: blue;">char</span>[] { <span style="color: #a31515;">':'</span> });
<span style="color: #2b91af;">TimeSpan</span> arrivalTime = <span style="color: blue;">new</span> <span style="color: #2b91af;">TimeSpan</span>(<span style="color: #2b91af;">Convert</span>.ToInt32(end[0]), <span style="color: #2b91af;">Convert</span>.ToInt32(end[1]), <span style="color: #2b91af;">Convert</span>.ToInt32(end[2]));
<span style="color: blue;">int</span> OIDStopToStop = <span style="color: #2b91af;">Convert</span>.ToInt32(row.get_Value(idxFieldOIDStopToStop));
<span style="color: blue;">double</span> seconds = arrivalTime.Subtract(departureTime).TotalSeconds;
stopToStopTime.Add(<span style="color: blue;">new</span> <span style="color: #2b91af;">StopToStopTime</span>(OIDStopToStop, departureTime, arrivalTime, seconds));
row = cursor.NextRow();
}
}
}</pre>
<br />
<br />
Una volta creata la dll occorre registrarla con ESRIRegAsm:<br />
<br />
"%COMMONPROGRAMFILES(x86)%\ArcGIS\bin\ESRIRegAsm" /p:desktop Studioat.ArcGIS.DepartureTimeEvaluator.dll<br />
<br />
<br />
Mentre se vogliamo utilizzarla anche in ArcGIS Server utilizziamo il comando:<br />
<br />
"%COMMONPROGRAMFILES%\ArcGIS\bin\ESRIRegAsm" Studioat.ArcGIS.DepartureTimeEvaluator.dll /p:server<br />
<br />
In questo ultimo caso occorre compilare la dll in Platform target con <em><strong>Any CPU</strong></em><br />
<strong><em></em></strong><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDs5PPT6dLNEeYrXqEBOJLSJ0kao4vlxya4SQYFY-3FXzFh4uyFLoUY6tumVykAGb1tBGuGb8Z-Ra7MnS82AyrsuBSwQM-HN_mABYJZq2sSwKEwDIrGkn6bdxzB5UrkejMonWn6S7M3tnd/s1600/evaluator4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="378" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDs5PPT6dLNEeYrXqEBOJLSJ0kao4vlxya4SQYFY-3FXzFh4uyFLoUY6tumVykAGb1tBGuGb8Z-Ra7MnS82AyrsuBSwQM-HN_mABYJZq2sSwKEwDIrGkn6bdxzB5UrkejMonWn6S7M3tnd/s640/evaluator4.png" width="640" /></a></div>
<br />
<strong><em></em></strong><br />
Ma veniamo ora ad un esempio:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSfG7vYjnWUrCJgK5A5ixO4NrzMmfEdH1hloZwbKCkUiDJNLLCA26Jieg-qOv5qu8aztH8WAzNmvB1iS-BlzBCNr64NnFnCu0pB9p-_dalLwKzaWmoJK1uVzVhZxPEi6IpSNAX54LRlsel/s1600/evaluator5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSfG7vYjnWUrCJgK5A5ixO4NrzMmfEdH1hloZwbKCkUiDJNLLCA26Jieg-qOv5qu8aztH8WAzNmvB1iS-BlzBCNr64NnFnCu0pB9p-_dalLwKzaWmoJK1uVzVhZxPEi6IpSNAX54LRlsel/s640/evaluator5.png" width="626" /></a></div>
<strong><em></em></strong><br />
Una volta impostato l'evaluator agli elementi edge dell'attributo di tipo costo creiamo un nuovo layer di analisi Route.<br />
In <em>Route Properties</em> selezioniamo la checkbox <em>Use Start Time </em>ed impostiamo un orario di partenza (ad esempio 8.00) mentre chiaramente in <em>Impedance</em> è impostato il costo sul quale è impostato il nostro evaluator ed indichiamo due stop.<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjApGd3GWBsbj4aDSi3po3Erouukmv3i4lZRUpk0LN0V8dW6A5IpUzKjBH5ihY3k7YY4FWb5zty2FHzu2L1h3A37-ut4R86_24AoW6M_W4Bb5ajgYKEZ4nFiYhfZ2L-otwnc1R1RqbRHaFz/s1600/evaluator6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjApGd3GWBsbj4aDSi3po3Erouukmv3i4lZRUpk0LN0V8dW6A5IpUzKjBH5ihY3k7YY4FWb5zty2FHzu2L1h3A37-ut4R86_24AoW6M_W4Bb5ajgYKEZ4nFiYhfZ2L-otwnc1R1RqbRHaFz/s640/evaluator6.png" width="640" /></a></div>
<br />
<br />
A questo punto eseguiamo con il Solve per determinare il percorso che minimizza la impedance:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhosia0CoyBOVnX-000e7WTbGkuci_1LbG_g9E19kFnj6wsrisWsX5__4knX6bEvXROwzwKjLWIeRPAhcIGPIp2_KTK-4vUDmKBTqUauK_StVmHMpJWXhsJvScFdV0R3aonJpDYZ6FYVRgu/s1600/Evaluator7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhosia0CoyBOVnX-000e7WTbGkuci_1LbG_g9E19kFnj6wsrisWsX5__4knX6bEvXROwzwKjLWIeRPAhcIGPIp2_KTK-4vUDmKBTqUauK_StVmHMpJWXhsJvScFdV0R3aonJpDYZ6FYVRgu/s640/Evaluator7.png" width="640" /></a></div>
<br />
<br />
Riepilogando:<br />
- partenza alle 8.00<br />
- partenza più vicina e uguale o superiore alle 8:00 per il tratto 2 è alle 8:10:50 e arrivo alle 8:12:30<br />
- partenza più vicina e uguale o superiore alle 8:12:30 per il tratto 3 è alle 8:12:30 e arrivo alle 8:34:30<br />
<br />
Quindi l'end time è 8:34:30.<br />
<br />
Ma se dovessimo modificare un orario, ad esempio quello del tratto 11 alla data di arrivo 8:33:20 il percorso come possiamo vedere cambia. Possiamo vederlo dinamicamente perché nell'evaluator per il metodo <em>Refresh</em> rifacciamo leggere la schedulazione che consente così all'evaluator di rilevare i dati in tabella aggiornati.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjH85tC7c_MXzPAhVGA8aQltiGjyGRZ-GyjLka9o_ugRdJ81lkn2UEMsfhRHfpxgHpEMpVqhVgGJHaVuaiuMrmtBSDN6wV6PDvQOiJh_aUhsgDQ3AHbRmr_BAFCJJsCO7AjZDWLPOrUuXCY/s1600/evaluator8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="624" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjH85tC7c_MXzPAhVGA8aQltiGjyGRZ-GyjLka9o_ugRdJ81lkn2UEMsfhRHfpxgHpEMpVqhVgGJHaVuaiuMrmtBSDN6wV6PDvQOiJh_aUhsgDQ3AHbRmr_BAFCJJsCO7AjZDWLPOrUuXCY/s640/evaluator8.png" width="640" /></a></div>
<br />
Riepilogando:<br />
- partenza alle 8.00<br />
- partenza più vicina e uguale o superiore alle 8:00 per il tratto 2 è alle 8:10:50 e arrivo alle 8:12:30<br />
- partenza più vicina e uguale o superiore alle 8:12:30 per il tratto 9 è alle 8:20:20 e arrivo alle 8:30:50<br />
- partenza più vicina e uguale o superiore alle 8:30:50 per il tratto 10 è alle 8:30:50 e arrivo alle 8:32:30<br />
- partenza più vicina e uguale o superiore alle 8:32:30 per il tratto 11 è alle 8:32:30 e arrivo alle 8:33:20<br />
<br />
Quindi l'end time è 8:33:20 e quindi inferiore al caso precedente. Ecco perché il solver ha scelto questo percorso.<br />
<br />
Infine per poter andare in debug con il custom evaluator possiamo, come avviene, per le altre personalizzazioni in ArcGis Desktop impostare l'exe di ArcMap in <strong>Start external program</strong> nella sezione Debug delle proprietà del progetto.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0iznB51qPK1Slru4UqtNQOu814pCTPdGgZAr9sN9Bt936RCxMpsmaYIh3M9-3B0hVVMOG8GjNDkpBmYUamNVzM4mLDptNWg-agVmvdyTVnRjGatgWFhbpWDjWWabM1u0yRU0o3Zt02xKZ/s1600/Evaluator9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="460" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0iznB51qPK1Slru4UqtNQOu814pCTPdGgZAr9sN9Bt936RCxMpsmaYIh3M9-3B0hVVMOG8GjNDkpBmYUamNVzM4mLDptNWg-agVmvdyTVnRjGatgWFhbpWDjWWabM1u0yRU0o3Zt02xKZ/s640/Evaluator9.png" width="640" /></a></div>
<br />
<br />
<a href="http://sit.sistemigis.it/samples/transit/">Qui</a> potete vedere un sample del custom evaluator esposto via ArcGIS for Server con la stessa logica descritta nel documento PDF di questo <a href="http://www.arcgis.com/home/item.html?id=0fa52a75d9ba4abcad6b88bb6285fae1">link</a>.<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902007 9.255947099999957620.068166199999997 -32.052646900000042 71.1122352 50.564541099999957tag:blogger.com,1999:blog-8323071861123024882.post-50398451535230769272013-04-30T21:44:00.000+02:002013-06-30T21:45:22.984+02:00Package PythonQuando abbiamo un certo numero di classi e funzioni, è consigliabile separarli in moduli (scripts). I moduli potrebbero crescere e quindi potreste considerare di raggrupparli in package. Un package in sostanza è un altro tipo di modulo che può contenere altri moduli correlati tra loro per funzionalità. Un modulo è memorizzato come un file .py mentre un package è una cartella. In pratica un package è una cartella con un file chiamato __init__.py al suo interno.<br />
Questo file definisce attributi e metodi del package; esso comunque può anche essere vuoto ma deve essere presente. Se il file non esiste la cartella è una semplice cartella e quindi il package non può essere importato mentre se viceversa il file esiste è possibile importare un package come modulo.<br />
Ad esempio importiamo ArcPy utilizzando <em>import arcpy</em> ma non è presente uno script arcpy.py bensì una cartella di nome arcpy nella quale è presente un file di nominato __init__.py<br />
<br />
Qui sotto possiamo vedere la cartella arcpy dove possiamo notare la presenza del file __init__.py in essa contenuta.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7tja4y-fjnEkJTR5u7XoJlXDCwboPgovMv-u5JGiHfPrz8FRF8hyphenhyphenRkuhVK64g5Sa1U3M4wHipGbF8UFHn-H93SLiVXmQcKfznYQbKDiyAq01eA37HvstkvRV-HENHy7J42HEelq-xsagg/s914/package1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7tja4y-fjnEkJTR5u7XoJlXDCwboPgovMv-u5JGiHfPrz8FRF8hyphenhyphenRkuhVK64g5Sa1U3M4wHipGbF8UFHn-H93SLiVXmQcKfznYQbKDiyAq01eA37HvstkvRV-HENHy7J42HEelq-xsagg/s1600/package1.png" /></a></div>
<br />
<br />
Premesso che molti IDE Python facilitano la creazione della struttura ed il setup per la distribuzione dei package, vediamo come possiamo crearci il nostro semplicissimo package.<br />
<br />
Un volta stabilito il nome del package, ad esempio geometrypy, ci creiamo una cartella con questo nome ed in questa cartella inseriamo un file nominato __init__.py<br />
<br />
La struttura sarà tipo:<br />
<br />
geometrypy<br />
__init__.py<br />
utils.py<br />
polyline.py<br />
....<br />
<br />
In PyCharm possiamo farlo automaticamente:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEbXfeKV5MpkCNJE_lN9XXaqCVCcL_hlxinEUS6K23d2vDRxG49Rfp4ccIkiSE1UWaN0J6SsvC5gYp_4ROkdp8xVyvkKIDRqUijWZY-hOWkiuT-iYOXKfYq5ewRtow1zrzASS8A7hHnwYH/s740/package2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEbXfeKV5MpkCNJE_lN9XXaqCVCcL_hlxinEUS6K23d2vDRxG49Rfp4ccIkiSE1UWaN0J6SsvC5gYp_4ROkdp8xVyvkKIDRqUijWZY-hOWkiuT-iYOXKfYq5ewRtow1zrzASS8A7hHnwYH/s1600/package2.png" /></a></div>
<br />
<br />
<br />
Diamo il nome al package:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqY5I8SADSp9jWeszjIPBh-9uCi7hrPkgH7CjxrYmQDReR3XgkcdNl0LdsZwi9_KFfJo78UsdlQfDeiyUYA2nTOnJf8N28JEZH-kCeLjkqmt177NQ27642Y3obcaEESywOo4CP38kooQzj/s423/package3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqY5I8SADSp9jWeszjIPBh-9uCi7hrPkgH7CjxrYmQDReR3XgkcdNl0LdsZwi9_KFfJo78UsdlQfDeiyUYA2nTOnJf8N28JEZH-kCeLjkqmt177NQ27642Y3obcaEESywOo4CP38kooQzj/s1600/package3.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
Aggiungiamo il nome modulo (ad esempio utils.py):</div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgotzBGTwQ5v7btc2_MtLbLe6nbsVdPKi1uicvYB7xmH6MRUknBV-ms9bVgGP-669vLkSlFQI82IWgSxF-Z1C-aYNiJ8dy6xOwwqWj_cRsc31NmYNDBI6LrEByKLTtoCr34mIHN0CNzXOXz/s1211/package4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgotzBGTwQ5v7btc2_MtLbLe6nbsVdPKi1uicvYB7xmH6MRUknBV-ms9bVgGP-669vLkSlFQI82IWgSxF-Z1C-aYNiJ8dy6xOwwqWj_cRsc31NmYNDBI6LrEByKLTtoCr34mIHN0CNzXOXz/s1600/package4.png" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<br />
Poiché i package potrebbero avere una struttura complessa e magari c'è l'esigenza di distribuirli ad altri utenti affinché altri li possano utilizzare, nella dotazione standard è presente <a href="http://docs.python.org/2/library/distutils.html" target="_blank">distutils</a> per la distribuzione.<br />
In questo caso, essendo il package molto semplice, il tutto si riduce al file setup.py<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC5-Mdgjm8cUm0nF-O7TrKQzVCoHug0dYP2CPl0XaIp-yI7oNkrzFFQF4Kf2tA6D8kf_nRmgqZu5d4y0nUhvPS1tayveMTz-sZx8nbcAlPVJ7_XJJ6LMPWxGiHjBJacyDi4ylDhIOWZQGO/s609/package5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC5-Mdgjm8cUm0nF-O7TrKQzVCoHug0dYP2CPl0XaIp-yI7oNkrzFFQF4Kf2tA6D8kf_nRmgqZu5d4y0nUhvPS1tayveMTz-sZx8nbcAlPVJ7_XJJ6LMPWxGiHjBJacyDi4ylDhIOWZQGO/s1600/package5.png" /></a></div>
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN37-CctUztW98cjL4vR8KKxxaSMMUPmPhkpwJf0T7OykTrpxLSqAPwZo19SqWLW5KFpi8v-t2lcMlUIDLSp51M75qR052GLCeq3oyT1a47WBNFrC-f3rjtMCOV_4IUV97fNWkc4Ba6jtE/s477/package6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN37-CctUztW98cjL4vR8KKxxaSMMUPmPhkpwJf0T7OykTrpxLSqAPwZo19SqWLW5KFpi8v-t2lcMlUIDLSp51M75qR052GLCeq3oyT1a47WBNFrC-f3rjtMCOV_4IUV97fNWkc4Ba6jtE/s1600/package6.png" /></a></div>
<br />
<br />
Viene creato il file setup.py<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG7NFbRY60vxQ9pLeXf2ymvRPZILDfEZG2XVqgpwkQ4Oa7qT5ycGoZH-H3Ly7cK0221gAjsqyhBkBxsV0G7drxk3gdmExbw-8sdkgldQzMyP5Zytvt41J0m9tGJi6KhbEAi7LOynf9rK0n/s744/package7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG7NFbRY60vxQ9pLeXf2ymvRPZILDfEZG2XVqgpwkQ4Oa7qT5ycGoZH-H3Ly7cK0221gAjsqyhBkBxsV0G7drxk3gdmExbw-8sdkgldQzMyP5Zytvt41J0m9tGJi6KhbEAi7LOynf9rK0n/s1600/package7.png" /></a></div>
<br />
A questo punto creiamo il pacchetto autoinstallante così da agevolare l'installazione:<br />
<br />
selezioniamo <strong><em>Run setup.py Task...</em></strong><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcGNXtRrKw1LftW8YdZ5wsDEG-SfiTpGaRKjtQKFPIjFJAa6aE6rw1ktqjYQdfaUlVqNTmm3UtleMj-BZG0l6zXom65GgQo7-xduyDYwW98jaSn6vYFR6URFc053_QYEEZh5UNeFCKp4pz/s722/package8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcGNXtRrKw1LftW8YdZ5wsDEG-SfiTpGaRKjtQKFPIjFJAa6aE6rw1ktqjYQdfaUlVqNTmm3UtleMj-BZG0l6zXom65GgQo7-xduyDYwW98jaSn6vYFR6URFc053_QYEEZh5UNeFCKp4pz/s1600/package8.png" /></a></div>
<br />
<br />
Creiamo un autoinstallante per l'ambiente Windows<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilIL37ttj-s3LwZEgloGPSL12CmwuFfX8E5VbIZ7AKmQZRzi19yyR3i-k0dWfqvKVuI8AuR_-uRp_r6v9gxgYe8wu-I-JNYw6Uw5hJSXidhyWI64Qj5aZzpKuIMI9L1RPXxwQZT9GGrYLf/s601/package9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilIL37ttj-s3LwZEgloGPSL12CmwuFfX8E5VbIZ7AKmQZRzi19yyR3i-k0dWfqvKVuI8AuR_-uRp_r6v9gxgYe8wu-I-JNYw6Uw5hJSXidhyWI64Qj5aZzpKuIMI9L1RPXxwQZT9GGrYLf/s1600/package9.png" /></a></div>
<br />
Inseriamo alcuni paramenti utilizzati per la generazione del pacchetto autoinstallante<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhws07t2SDxMcoOeCchWljSm8d9081dqKQUAXSr_qFrrhK2zBSm4ftkNw_FRL6us0o19K0tk5vx_aCBgbh-N_oN1sI9gfYYDhTdPiHZz5i0Es_mrgCXT7fI4vnv5BSOgxcn6O5sJV_R1jrG/s712/package10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhws07t2SDxMcoOeCchWljSm8d9081dqKQUAXSr_qFrrhK2zBSm4ftkNw_FRL6us0o19K0tk5vx_aCBgbh-N_oN1sI9gfYYDhTdPiHZz5i0Es_mrgCXT7fI4vnv5BSOgxcn6O5sJV_R1jrG/s1600/package10.png" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhAnLQkwy6c4Ay2o2HT8IeNoN-jlx_HwLSfVxlVN5b55d1gpGwo-Vjhq3cbYU41CCH2Tpgecr1SOtChb4t5QtgxdGL67esH3KwysnrB57BEggTeY_2z3RigYfuNvYzOC6da8LS6iAN0ceN/s921/package11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhAnLQkwy6c4Ay2o2HT8IeNoN-jlx_HwLSfVxlVN5b55d1gpGwo-Vjhq3cbYU41CCH2Tpgecr1SOtChb4t5QtgxdGL67esH3KwysnrB57BEggTeY_2z3RigYfuNvYzOC6da8LS6iAN0ceN/s1600/package11.png" /></a></div>
<br />
Una volta generato il file di installazione lo eseguiamo:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFf0GDlm6fwL84v9reP0dstIW0zNKffU2RpakDYQ1l54pBQcIx7WV9dt9iO8thdM2cxey76wer3go8jTiIlzAZPD8JzawB7ue__wcb8pLaV3EzIe3c5fU82Yzm-WoZ2W9Ochi6tKzHouAR/s871/package12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFf0GDlm6fwL84v9reP0dstIW0zNKffU2RpakDYQ1l54pBQcIx7WV9dt9iO8thdM2cxey76wer3go8jTiIlzAZPD8JzawB7ue__wcb8pLaV3EzIe3c5fU82Yzm-WoZ2W9Ochi6tKzHouAR/s1600/package12.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQskWz2Q-aXeCf0kIQEPaF7y4d5OPJMFHNAR9o_AIBkaQ9coeuNKOAIcTZdhtLoNPgX86p6vnIg0AlZYvXs4DNdYqmOcm9MkSbO937AtODJ3t_UiOd_KMG4r2xWS18OpTh1Avr6Cq4UwhJ/s1130/package13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQskWz2Q-aXeCf0kIQEPaF7y4d5OPJMFHNAR9o_AIBkaQ9coeuNKOAIcTZdhtLoNPgX86p6vnIg0AlZYvXs4DNdYqmOcm9MkSbO937AtODJ3t_UiOd_KMG4r2xWS18OpTh1Avr6Cq4UwhJ/s1600/package13.png" /></a></div>
<br />
A questo punto utilizziamo il nostro package:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGdpsnfhzvkMH2CvgYPvP_1jJzBU5ygwCpfsmy103yR3moJ3naslFNraJnt3RhqXSSHL3G2FgyDM4rdswQ4mojhaMc0BaDXKWvWU6OYwi6Gf1OFxnejZsRn0soYnby3YautzMVOdc3K3CY/s1067/package14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGdpsnfhzvkMH2CvgYPvP_1jJzBU5ygwCpfsmy103yR3moJ3naslFNraJnt3RhqXSSHL3G2FgyDM4rdswQ4mojhaMc0BaDXKWvWU6OYwi6Gf1OFxnejZsRn0soYnby3YautzMVOdc3K3CY/s1600/package14.png" /></a></div>
<br />
<br />
Per disinstallare il package in <em><strong>Installazione Applicazioni</strong></em> di Windows in Panello di controllo selezionare la voce <em><strong>Python 2.7 geometrypy</strong></em>.<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902007 9.255947099999957620.068166199999997 -32.052646900000042 71.1122352 50.564541099999957tag:blogger.com,1999:blog-8323071861123024882.post-66317269055001176922013-03-31T20:49:00.000+02:002013-05-14T16:14:06.471+02:00Tutto il resto è Layar ... e non ho detto layer ma Layar Layar Layar ...Nel 2010 avevo fatto riferimento alla realtà aumentata accennando a <a href="http://nicogis.blogspot.it/2010/06/realta-aumentata-augmented-reality-ar.html" target="_blank">Layar</a>. In questo post vediamo come esporre i nostri servizi ArcGIS Server a <a href="http://www.layar.com/" target="_blank">Layar</a> e visualizzarli geolocalizzati in prossimità del luogo in cui si trova l'utente. I dati sono forniti sotto forma di livelli chiamati layer, che non sono altro che servizi web di tipo REST. I layer sono mantenuti dai pubblicatori mentre Layar è responsabile della loro convalida nel processo di pubblicazione che normalmente avviene entro 5 giorni dalla richiesta di pubblicazione. Poiché stiamo parlando di realtà aumentata su dispositivi mobile (abbiamo a disposizione sia l'app per <a href="https://www.layar.com/download/" target="_blank">iOS</a> che per <a href="https://www.layar.com/download/" target="_blank">Android</a>) per poter funzionare Layar necessità di GPS, magnetometro (bussola), fotocamera e accelerometro, nonché connessione a internet per ricevere i dati dei servizi online. Il nostro dispositivo inquadra in tempo reale l'ambiente circostante e al mondo reale vengono sovrapposti i livelli di contenuto (layer).<br />
<br />
Vediamo come funziona:<br />
<ol>
<li>un utente lancia il Layer browser sul suo dispositivo mobile;</li>
<li>il Layar Client invia la richiesta al Layar server;</li>
<li>in base alla richiesta il Layar Server restituisce la definizione dei layer pubblicati;</li>
<li>una lista dei layer viene inviata dal Layer Server e visualizzata sul Layar Client;</li>
<li>un utente seleziona un layer dalla lista;</li>
<li>una richiesta getPOIs è inviata al Layar Server;</li>
<li>il Layar Server trasferisce la richiesta al Layer Service Provider di quel layer;</li>
<li>il Layer Service Provider restituisce il contenuto basandosi sulle specifiche delle Developer API (response getPOIs) al Layar Server;</li>
<li>il Layar Server convalida la response getPOIs e la invia al Layar Client</li>
<li>il Layar Client visualizza i POI. </li>
</ol>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgquSZCN93K6bvRXyEWTJzZJ3dsH-BsbTjUmiyRWntYrL1zVeaX3V3SHMdSuih8gA8VJognLY3PCcwAidZxGLIwlhsrriF1s1czVFqwpLK7HmJYW7OpCHEvHg52xtLSsfXNiebNcgrwFboN/s1600/Layar_Architecture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgquSZCN93K6bvRXyEWTJzZJ3dsH-BsbTjUmiyRWntYrL1zVeaX3V3SHMdSuih8gA8VJognLY3PCcwAidZxGLIwlhsrriF1s1czVFqwpLK7HmJYW7OpCHEvHg52xtLSsfXNiebNcgrwFboN/s640/Layar_Architecture.png" width="640" /></a></div>
<br />
<br />
Nella <a href="http://layar.com/documentation/browser/api/" target="_blank">documentazione per lo sviluppatore</a> potete trovare tutti i dettagli sull'architettura della piattaforma Layar.<br />
<br />
Ora vediamo come creare un semplice Layer Service Providers per esporre i nostri POI direttamente da ArcGIS Server.<br />
Come possiamo vedere dalla <a href="http://layar.com/documentation/browser/api/" target="_blank">documentazione</a>, tutte le chiamate sono RESTful cosicché aderiscono ad una architettura REST. Correntemente solo una chiamata HTTP GET è stata definita per recuperare le risorse ed è <a href="http://layar.com/documentation/browser/api/getpois-request/" target="_blank">GetPOIs</a>.<br />
<br />
In ArcGIS Server possiamo crearci una SOE REST che restituisce un JSON che aderisce a <a href="http://layar.com/documentation/browser/api/getpois-response/" target="_blank">GetPOIs response</a>.<br />
In questo esempio i dati di input (request: layerName, lon, lat) e di output (response:layer, hotspots(id, anchor, text(title, description, footnote)), title, errorCode, errorString) sono solo quelli obbligatori ma nella documentazione potete trovarne molti altri opzionali che possono arricchire le funzionalità dei vostri POI.<br />
Per semplificarci ulteriormente la vita, il raggio di ricerca viene impostato a livello di proprietà SOE ma anche il numero di POI restituiti è impostato a livello di proprietà SOE e restituiamo i più vicini ma le API ci permettono di gestire il raggio, il paging ecc.<br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="color: green;">//-----------------------------------------------------------------------</span>
<span style="color: green;">// <copyright file="LayarSOE.cs" company="Studio A&T s.r.l."></span>
<span style="color: green;">// Copyright (c) Studio A&T s.r.l. All rights reserved.</span>
<span style="color: green;">// </copyright></span>
<span style="color: green;">// <author>Nicogis</author></span>
<span style="color: green;">//-----------------------------------------------------------------------</span>
<span style="color: blue;">namespace</span> Studioat.ArcGis.Soe.Rest
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Collections.Generic;
<span style="color: blue;">using</span> System.Collections.Specialized;
<span style="color: blue;">using</span> System.Diagnostics.CodeAnalysis;
<span style="color: blue;">using</span> System.Globalization;
<span style="color: blue;">using</span> System.Linq;
<span style="color: blue;">using</span> System.Reflection;
<span style="color: blue;">using</span> System.Runtime.InteropServices;
<span style="color: blue;">using</span> System.Text;
<span style="color: blue;">using</span> ESRI.ArcGIS.Carto;
<span style="color: blue;">using</span> ESRI.ArcGIS.esriSystem;
<span style="color: blue;">using</span> ESRI.ArcGIS.Geodatabase;
<span style="color: blue;">using</span> ESRI.ArcGIS.Geometry;
<span style="color: blue;">using</span> ESRI.ArcGIS.Server;
<span style="color: blue;">using</span> ESRI.ArcGIS.SOESupport;
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.NamingRules"</span>, <span style="color: #a31515;">"SA1300:ElementMustBeginWithUpperCaseLetter"</span>, Justification = <span style="color: #a31515;">"Viewed."</span>)]
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.NamingRules"</span>, <span style="color: #a31515;">"SA1305:FieldNamesMustNotUseHungarianNotation"</span>, Justification = <span style="color: #a31515;">"Viewed."</span>)]
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.NamingRules"</span>, <span style="color: #a31515;">"SA1306:FieldNamesMustBeginWithLowerCaseLetter"</span>, Justification = <span style="color: #a31515;">"Viewed."</span>)]
[<span style="color: #2b91af;">SuppressMessage</span>(<span style="color: #a31515;">"StyleCop.CSharp.DocumentationRules"</span>, <span style="color: #a31515;">"SA1650:ElementDocumentationMustBeSpelledCorrectly"</span>, Justification = <span style="color: #a31515;">"viewed."</span>)]
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> class Layar SOE</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
[<span style="color: #2b91af;">ComVisible</span>(<span style="color: blue;">true</span>)]
[<span style="color: #2b91af;">Guid</span>(<span style="color: #a31515;">"ec27c9f5-a7c4-4be6-8543-d170762e8604"</span>)]
[<span style="color: #2b91af;">ClassInterface</span>(<span style="color: #2b91af;">ClassInterfaceType</span>.None)]
[<span style="color: #2b91af;">ServerObjectExtension</span>(<span style="color: #a31515;">"MapServer"</span>,
AllCapabilities = <span style="color: #a31515;">""</span>,
DefaultCapabilities = <span style="color: #a31515;">""</span>,
Description = <span style="color: #a31515;">"Layar SOE"</span>,
DisplayName = <span style="color: #a31515;">"Layar SOE"</span>,
Properties = <span style="color: #a31515;">"NearestPOIs = 10;Radius = 500"</span>,
HasManagerPropertiesConfigurationPane = <span style="color: blue;">false</span>,
SupportsREST = <span style="color: blue;">true</span>,
SupportsSOAP = <span style="color: blue;">false</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">LayarSOE</span> : <span style="color: #2b91af;">IServerObjectExtension</span>, <span style="color: #2b91af;">IObjectConstruct</span>, <span style="color: #2b91af;">IRESTRequestHandler</span>
{
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> name of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> soeName;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> properties of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IPropertySet</span> configProps;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Helper ServerObject</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IServerObjectHelper</span> serverObjectHelper;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> logger of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">ServerLogger</span> logger;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> request handler</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IRESTRequestHandler</span> reqHandler;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> number of nearest POIs</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">int</span> nearestPOIs;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> radius for POIs</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">int</span> radius;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> List of POILayerInfo</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">POILayerInfo</span>> poiLayerInfos;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Initializes a new instance of the </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"LayarSOE"</span><span style="color: grey;">/></span><span style="color: green;"> class</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> LayarSOE()
{
<span style="color: blue;">this</span>.soeName = <span style="color: blue;">this</span>.GetType().Name;
<span style="color: blue;">this</span>.logger = <span style="color: blue;">new</span> <span style="color: #2b91af;">ServerLogger</span>();
<span style="color: blue;">this</span>.reqHandler = <span style="color: blue;">new</span> <span style="color: #2b91af;">SoeRestImpl</span>(<span style="color: blue;">this</span>.soeName, <span style="color: blue;">this</span>.CreateRestSchema()) <span style="color: blue;">as</span> <span style="color: #2b91af;">IRESTRequestHandler</span>;
}
<span style="color: blue;"> #region</span> IServerObjectExtension Members
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> init event of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"pSOH"</span><span style="color: grey;">></span><span style="color: green;">Helper ServerObject</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Init(<span style="color: #2b91af;">IServerObjectHelper</span> pSOH)
{
<span style="color: blue;">this</span>.serverObjectHelper = pSOH;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> shutdown event of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Shutdown()
{
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> IObjectConstruct Members
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> costruct event of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"props"</span><span style="color: grey;">></span><span style="color: green;">properties of soe</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Construct(<span style="color: #2b91af;">IPropertySet</span> props)
{
<span style="color: blue;">this</span>.configProps = props;
<span style="color: blue;">this</span>.nearestPOIs = <span style="color: #2b91af;">Convert</span>.ToInt32(<span style="color: blue;">this</span>.configProps.GetProperty(<span style="color: #a31515;">"NearestPOIs"</span>));
<span style="color: blue;">this</span>.radius = <span style="color: #2b91af;">Convert</span>.ToInt32(<span style="color: blue;">this</span>.configProps.GetProperty(<span style="color: #a31515;">"Radius"</span>));
<span style="color: blue;">this</span>.poiLayerInfos = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">POILayerInfo</span>>();
<span style="color: blue;">this</span>.GetPOILayerInfos();
}
<span style="color: blue;"> #endregion</span>
<span style="color: blue;"> #region</span> IRESTRequestHandler Members
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> get schema of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">schema of soe</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">string</span> GetSchema()
{
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.reqHandler.GetSchema();
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Handler of request rest</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"Capabilities"</span><span style="color: grey;">></span><span style="color: green;">capabilities of soe</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"resourceName"</span><span style="color: grey;">></span><span style="color: green;">name of resource</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationName"</span><span style="color: grey;">></span><span style="color: green;">name of operation</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationInput"</span><span style="color: grey;">></span><span style="color: green;">input of operation</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">format of output</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">list of request properties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">list of response properties </span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response in byte</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">byte</span>[] HandleRESTRequest(<span style="color: blue;">string</span> Capabilities, <span style="color: blue;">string</span> resourceName, <span style="color: blue;">string</span> operationName, <span style="color: blue;">string</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.reqHandler.HandleRESTRequest(Capabilities, resourceName, operationName, operationInput, outputFormat, requestProperties, <span style="color: blue;">out</span> responseProperties);
}
<span style="color: blue;"> #endregion</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> create schema of soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">resource of soe</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">RestResource</span> CreateRestSchema()
{
<span style="color: #2b91af;">RestResource</span> rootRes = <span style="color: blue;">new</span> <span style="color: #2b91af;">RestResource</span>(<span style="color: blue;">this</span>.soeName, <span style="color: blue;">false</span>, <span style="color: blue;">this</span>.RootResHandler);
<span style="color: #2b91af;">RestResource</span> item = <span style="color: blue;">new</span> <span style="color: #2b91af;">RestResource</span>(<span style="color: #a31515;">"POILayers"</span>, <span style="color: blue;">true</span>, <span style="color: blue;">new</span> <span style="color: #2b91af;">ResourceHandler</span>(<span style="color: blue;">this</span>.POILayer));
rootRes.resources.Add(item);
<span style="color: #2b91af;">RestOperation</span> getPOIsOperation = <span style="color: blue;">new</span> <span style="color: #2b91af;">RestOperation</span>(<span style="color: #a31515;">"getPOIs"</span>, <span style="color: blue;">new</span> <span style="color: blue;">string</span>[] { <span style="color: #a31515;">"lon"</span>, <span style="color: #a31515;">"lat"</span>, <span style="color: #a31515;">"layerName"</span> }, <span style="color: blue;">new</span> <span style="color: blue;">string</span>[] { <span style="color: #a31515;">"json"</span> }, <span style="color: blue;">this</span>.getPOIsOperationHandler);
item.operations.Add(getPOIsOperation);
<span style="color: blue;">return</span> rootRes;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> handler of resource root</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"boundVariables"</span><span style="color: grey;">></span><span style="color: green;">list of variables bound</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">format of output</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">list of request properties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">list of response properties </span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">root resource in format output in byte</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">byte</span>[] RootResHandler(<span style="color: #2b91af;">NameValueCollection</span> boundVariables, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"application/json\"}"</span>;
<span style="color: #2b91af;">JsonObject</span> result = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
<span style="color: #2b91af;">AddInPackageAttribute</span> addInPackage = (<span style="color: #2b91af;">AddInPackageAttribute</span>)<span style="color: #2b91af;">Assembly</span>.GetExecutingAssembly().GetCustomAttributes(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">AddInPackageAttribute</span>), <span style="color: blue;">false</span>)[0];
result.AddString(<span style="color: #a31515;">"agsVersion"</span>, addInPackage.TargetVersion);
result.AddString(<span style="color: #a31515;">"soeVersion"</span>, addInPackage.Version);
result.AddString(<span style="color: #a31515;">"author"</span>, addInPackage.Author);
result.AddString(<span style="color: #a31515;">"company"</span>, addInPackage.Company);
<span style="color: blue;">return</span> result.JsonByte();
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Handler operation Get POIs</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"boundVariables"</span><span style="color: grey;">></span><span style="color: green;">list of variables bound</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationInput"</span><span style="color: grey;">></span><span style="color: green;">input of operation</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">format of output</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">list of request properties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">list of response properties </span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response in byte</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">byte</span>[] getPOIsOperationHandler(<span style="color: #2b91af;">NameValueCollection</span> boundVariables, <span style="color: #2b91af;">JsonObject</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"application/json\"}"</span>;
<span style="color: blue;">string</span> layerName = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
<span style="color: blue;">bool</span> found = operationInput.TryGetString(<span style="color: #a31515;">"layerName"</span>, <span style="color: blue;">out</span> layerName);
<span style="color: blue;">if</span> (!found)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"layerName"</span>);
}
<span style="color: blue;">int</span> poiLayerID = <span style="color: #2b91af;">Convert</span>.ToInt32(boundVariables[<span style="color: #a31515;">"POILayersID"</span>], <span style="color: #2b91af;">CultureInfo</span>.InvariantCulture);
<span style="color: #2b91af;">POILayerInfo</span> poiLayerInfo = <span style="color: blue;">this</span>.GetPOILayerInfo(poiLayerID);
<span style="color: blue;">double</span>? lon;
found = operationInput.TryGetAsDouble(<span style="color: #a31515;">"lon"</span>, <span style="color: blue;">out</span> lon);
<span style="color: blue;">if</span> ((!found) || (!lon.HasValue))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"lon"</span>);
}
<span style="color: blue;">double</span>? lat;
found = operationInput.TryGetAsDouble(<span style="color: #a31515;">"lat"</span>, <span style="color: blue;">out</span> lat);
<span style="color: blue;">if</span> ((!found) || (!lat.HasValue))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArgumentNullException</span>(<span style="color: #a31515;">"lat"</span>);
}
<span style="color: #2b91af;">IFeatureClass</span> featureClass = <span style="color: blue;">this</span>.GetPOIFeatureClass(poiLayerInfo.Id);
<span style="color: #2b91af;">IPoint</span> point = <span style="color: blue;">new</span> <span style="color: #2b91af;">PointClass</span>();
point.X = lon.Value;
point.Y = lat.Value;
point.SpatialReference = <span style="color: #2b91af;">Helper</span>.GCS1984;
point.Project(poiLayerInfo.Extent.SpatialReference);
<span style="color: #2b91af;">ITopologicalOperator</span> topologicalOperator = point <span style="color: blue;">as</span> <span style="color: #2b91af;">ITopologicalOperator</span>;
<span style="color: #2b91af;">ISpatialFilter</span> spatialFilter = <span style="color: blue;">new</span> <span style="color: #2b91af;">SpatialFilterClass</span>();
spatialFilter.Geometry = topologicalOperator.Buffer(<span style="color: blue;">this</span>.radius);
spatialFilter.SpatialRel = <span style="color: #2b91af;">esriSpatialRelEnum</span>.esriSpatialRelIntersects;
spatialFilter.GeometryField = featureClass.ShapeFieldName;
<span style="color: #2b91af;">IFeatureCursor</span> featureCursor = <span style="color: blue;">null</span>;
<span style="color: #2b91af;">IDictionary</span><<span style="color: blue;">int</span>, <span style="color: blue;">double</span>> dictionaryDistances = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">int</span>, <span style="color: blue;">double</span>>();
<span style="color: blue;">try</span>
{
featureCursor = featureClass.Search(spatialFilter, <span style="color: blue;">true</span>);
<span style="color: #2b91af;">IFeature</span> feature = featureCursor.NextFeature();
<span style="color: blue;">while</span> (feature != <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">IGeometry</span> geometry = feature.ShapeCopy <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeometry</span>;
<span style="color: blue;">if</span> (geometry == <span style="color: blue;">null</span> || geometry.IsEmpty)
{
<span style="color: blue;">continue</span>;
}
<span style="color: #2b91af;">IProximityOperator</span> proximityOperator = feature.ShapeCopy <span style="color: blue;">as</span> <span style="color: #2b91af;">IProximityOperator</span>;
<span style="color: blue;">double</span> distance = proximityOperator.ReturnDistance(point);
dictionaryDistances.Add(feature.OID, distance);
feature = featureCursor.NextFeature();
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
<span style="color: blue;">finally</span>
{
<span style="color: #2b91af;">Marshal</span>.FinalReleaseComObject(featureCursor);
}
<span style="color: #2b91af;">JsonObject</span> result = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
result.AddString(<span style="color: #a31515;">"layer"</span>, layerName);
<span style="color: blue;">if</span> (dictionaryDistances.Count == 0)
{
result.AddLong(<span style="color: #a31515;">"errorCode"</span>, 21);
result.AddString(<span style="color: #a31515;">"errorString"</span>, <span style="color: #a31515;">"POIs not found!"</span>);
<span style="color: blue;">return</span> <span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(result.ToJson());
}
<span style="color: blue;">var</span> listPOIs = <span style="color: blue;">from</span> item <span style="color: blue;">in</span> dictionaryDistances <span style="color: blue;">orderby</span> item.Value <span style="color: blue;">ascending</span> <span style="color: blue;">select</span> item.Key;
<span style="color: blue;">if</span> (dictionaryDistances.Count > <span style="color: blue;">this</span>.nearestPOIs)
{
listPOIs = listPOIs.Take(<span style="color: blue;">this</span>.nearestPOIs);
}
<span style="color: blue;">int</span>[] listPOIOIDs = listPOIs.ToArray();
<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">JsonObject</span>> hotspots = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">JsonObject</span>>();
<span style="color: blue;">try</span>
{
featureCursor = featureClass.GetFeatures(listPOIOIDs, <span style="color: blue;">true</span>);
<span style="color: blue;">int</span> idxField = featureClass.FindField(<span style="color: #a31515;">"MyField"</span>);
<span style="color: #2b91af;">IFeature</span> feature = featureCursor.NextFeature();
<span style="color: blue;">while</span> (feature != <span style="color: blue;">null</span>)
{
<span style="color: blue;">string</span> valueField = <span style="color: #2b91af;">Convert</span>.ToString(feature.get_Value(idxField));
<span style="color: #2b91af;">JsonObject</span> hotspot = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
hotspot.AddString(<span style="color: #a31515;">"id"</span>, valueField);
<span style="color: #2b91af;">IPoint</span> poi = feature.ShapeCopy <span style="color: blue;">as</span> <span style="color: #2b91af;">IPoint</span>;
poi.Project(<span style="color: #2b91af;">Helper</span>.GCS1984);
hotspot.AddString(<span style="color: #a31515;">"anchor"</span>, <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"geo:{0},{1}"</span>, poi.Y.ToString(<span style="color: #2b91af;">Helper</span>.CultureUS), poi.X.ToString(<span style="color: #2b91af;">Helper</span>.CultureUS)));
<span style="color: #2b91af;">JsonObject</span> text = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
text.AddString(<span style="color: #a31515;">"title"</span>, <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"Id:{0}"</span>, valueField));
text.AddString(<span style="color: #a31515;">"description"</span>, <span style="color: blue;">string</span>.Empty);
text.AddString(<span style="color: #a31515;">"footnote"</span>, <span style="color: #a31515;">"Power by MyLayer"</span>);
hotspot.AddJsonObject(<span style="color: #a31515;">"text"</span>, text);
hotspot.AddString(<span style="color: #a31515;">"title"</span>, valueField);
<span style="color: green;">////hotspot.AddString("imageURL", ""); <100Kb 100x75</span>
hotspots.Add(hotspot);
feature = featureCursor.NextFeature();
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
<span style="color: blue;">finally</span>
{
<span style="color: #2b91af;">Marshal</span>.FinalReleaseComObject(featureCursor);
}
result.AddArray(<span style="color: #a31515;">"hotspots"</span>, hotspots.ToArray());
result.AddLong(<span style="color: #a31515;">"errorCode"</span>, 0);
result.AddString(<span style="color: #a31515;">"errorString"</span>, <span style="color: blue;">string</span>.Empty);
<span style="color: blue;">return</span> <span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(result.ToJson());
}
<span style="color: blue;">catch</span>
{
<span style="color: #2b91af;">JsonObject</span> result = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
result.AddString(<span style="color: #a31515;">"layer"</span>, layerName);
result.AddLong(<span style="color: #a31515;">"errorCode"</span>, 20);
result.AddString(<span style="color: #a31515;">"errorString"</span>, <span style="color: #a31515;">"Error return data"</span>);
<span style="color: blue;">return</span> <span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(result.ToJson());
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> resource POILayer</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"boundVariables"</span><span style="color: grey;">></span><span style="color: green;">list of variables bound</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">format of output</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">list of request properties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">list of response properties </span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">resource in byte</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">byte</span>[] POILayer(<span style="color: #2b91af;">NameValueCollection</span> boundVariables, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"application/json\"}"</span>;
<span style="color: blue;">if</span> (boundVariables[<span style="color: #a31515;">"POILayersID"</span>] == <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">JsonObject</span>[] objectArray = System.<span style="color: #2b91af;">Array</span>.ConvertAll(<span style="color: blue;">this</span>.poiLayerInfos.ToArray(), i => i.ToJsonObject());
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
jsonObject.AddArray(<span style="color: #a31515;">"poiLayers"</span>, objectArray);
<span style="color: blue;">return</span> jsonObject.JsonByte();
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">int</span> layerID = <span style="color: #2b91af;">Convert</span>.ToInt32(boundVariables[<span style="color: #a31515;">"POILayersID"</span>], <span style="color: #2b91af;">CultureInfo</span>.InvariantCulture);
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.GetPOILayerInfo(layerID).ToJsonObject().JsonByte();
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> get POILayerInfo from Id</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"poiLayerID"</span><span style="color: grey;">></span><span style="color: green;">value of poiLayerID</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">object POILayerInfo</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">POILayerInfo</span> GetPOILayerInfo(<span style="color: blue;">int</span> poiLayerID)
{
<span style="color: blue;">if</span> (poiLayerID < 0)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArgumentOutOfRangeException</span>(<span style="color: #a31515;">"poiLayerID"</span>);
}
<span style="color: #2b91af;">IMapServer3</span> serverObject = <span style="color: blue;">this</span>.GetMapServer();
<span style="color: #2b91af;">IMapLayerInfos</span> mapLayerInfos = serverObject.GetServerInfo(serverObject.DefaultMapName).MapLayerInfos;
<span style="color: blue;">long</span> count = mapLayerInfos.Count;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < count; i++)
{
<span style="color: #2b91af;">IMapLayerInfo</span> mapLayerInfo = mapLayerInfos.get_Element(i);
<span style="color: blue;">if</span> (mapLayerInfo.ID == poiLayerID)
{
<span style="color: blue;">return</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">POILayerInfo</span>(mapLayerInfo);
}
}
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ArgumentOutOfRangeException</span>(<span style="color: #a31515;">"poiLayerID"</span>);
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Feature Class from id of layer</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"poiLayerID"</span><span style="color: grey;">></span><span style="color: green;">id poi layer</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">feature class</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IFeatureClass</span> GetPOIFeatureClass(<span style="color: blue;">int</span> poiLayerID)
{
<span style="color: #2b91af;">IMapServer3</span> mapServer = <span style="color: blue;">this</span>.GetMapServer();
<span style="color: #2b91af;">IMapServerDataAccess</span> dataAccess = (<span style="color: #2b91af;">IMapServerDataAccess</span>)mapServer;
<span style="color: blue;">return</span> (<span style="color: #2b91af;">IFeatureClass</span>)dataAccess.GetDataSource(mapServer.DefaultMapName, poiLayerID);
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Get object MapServer of ServerObject </span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">object MapServer</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">IMapServer3</span> GetMapServer()
{
<span style="color: #2b91af;">IMapServer3</span> mapServer = <span style="color: blue;">this</span>.serverObjectHelper.ServerObject <span style="color: blue;">as</span> <span style="color: #2b91af;">IMapServer3</span>;
<span style="color: blue;">if</span> (mapServer == <span style="color: blue;">null</span>)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">LayarSOEException</span>(<span style="color: #a31515;">"Unable to access the map server."</span>);
}
<span style="color: blue;">return</span> mapServer;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> From service fills list of layer point</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">void</span> GetPOILayerInfos()
{
<span style="color: #2b91af;">IMapServer3</span> serverObject = <span style="color: blue;">this</span>.GetMapServer();
<span style="color: #2b91af;">IMapLayerInfos</span> mapLayerInfos = serverObject.GetServerInfo(serverObject.DefaultMapName).MapLayerInfos;
<span style="color: blue;">this</span>.poiLayerInfos = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">POILayerInfo</span>>();
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < mapLayerInfos.Count; i++)
{
<span style="color: #2b91af;">IMapLayerInfo</span> mapLayerInfo = mapLayerInfos.get_Element(i);
<span style="color: blue;">if</span> (mapLayerInfo.IsFeatureLayer)
{
<span style="color: #2b91af;">IFields</span> fields = mapLayerInfo.Fields;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> j = 0; j < fields.FieldCount; j++)
{
<span style="color: #2b91af;">IField</span> field = fields.get_Field(j);
<span style="color: blue;">if</span> (field.Type == <span style="color: #2b91af;">esriFieldType</span>.esriFieldTypeGeometry)
{
<span style="color: #2b91af;">IGeometryDef</span> geometryDef = field.GeometryDef;
<span style="color: blue;">if</span> (geometryDef.GeometryType == ESRI.ArcGIS.Geometry.<span style="color: #2b91af;">esriGeometryType</span>.esriGeometryPoint)
{
<span style="color: blue;">this</span>.poiLayerInfos.Add(<span style="color: blue;">new</span> <span style="color: #2b91af;">POILayerInfo</span>(mapLayerInfo));
}
<span style="color: blue;">break</span>;
}
}
}
}
}
}
}
</pre>
<br />
<br />
Possiamo proteggere il nostro servizio ArcGIS Server esponendo un proxy per ricevere e trasferire le chiamate dal Layar Platform. Il proxy genera un token ArcGIS Server dinamicamente per poter utilizzare il servizio al quale abbiamo abilitato la SOE o possiamo crearne uno statico che memorizziamo nel file di configurazione. Inoltre nel proxy possiamo gestire, ad esempio, le richieste firmate così da verificare se provengono da Layar e quindi farle passare o meno. La firma è conforme alla firma <a href="http://oauth.googlecode.com/svn/spec/core/1.0/" target="_blank">OAuth.</a> Quando si pubblica il layer su Layar Publishing Website, se si desidera avere delle richieste firmate, si possono impostare i parametri per l'autenticazione <a href="http://oauth.net/" target="_blank">OAuth</a> (OAuth signing required, OAuth consumer key e OAuth consumer secret).<br />
Il solo metodo di firma supportato è HMAC-SHA1 e la Signature Base String è generata utilizzando:<br />
<ol>
<li>metodo http: GET;</li>
<li>l'url della richiesta: nel nostro caso l'url del nostro proxy;</li>
<li>i parametri di richiesta normalizzati inclusi quelli di oauth ad esclusione di oauth_signature. I parametri di richiesta oauth usati da Layar Developer API sono: oauth_consumer_key, oauth_signature_method, oauth_timestamp, oauth_nonce, oauth_body_hash e oauth_version.</li>
</ol>
<br />
L'OAuth utilizzata è il 2-Legged che in sostanza è una OAuth senza utente. In pratica è un modo nel quale il consumer (Layar Platform) può fare una richiesta firmata ad un provider (nostro proxy) facendo leva sull'algoritmo di firma OAuth. Questo significa che il provider ha un livello di fiducia ulteriore con il consumer ed inoltre fornisce i dati al consumer senza la necessità di ottenere l'autorizzazione (token) dall'utente.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijJy4QMdVqTUj9-5remD4O9CsosPXEA2NxuUncFvRdvrJdjZimONxo9IPbaS84KqA4YCE1KzLpqwCntXnVSRXV-tlQflFiwDLLNu-33pU39MjXCRpT9CGgYr25wkIwIcc-MTPQdza0avhh/s1600/Layar1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="506" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijJy4QMdVqTUj9-5remD4O9CsosPXEA2NxuUncFvRdvrJdjZimONxo9IPbaS84KqA4YCE1KzLpqwCntXnVSRXV-tlQflFiwDLLNu-33pU39MjXCRpT9CGgYr25wkIwIcc-MTPQdza0avhh/s640/Layar1.png" width="640" /></a></div>
<br />
Ed ecco il nostro proxy. Per la verifica della firma della richiesta potete scaricare le due dll (OAuth.Net.Common e OAuth.Net.Components) da <a href="http://code.google.com/p/oauth-dot-net/">http://code.google.com/p/oauth-dot-net/</a><br />
<br />
<pre style="background: white; color: black; font-family: Consolas; font-size: 13px;"><span style="background: yellow;"><%</span><span style="color: blue;">@</span> <span style="color: maroon;">WebHandler</span> <span style="color: red;">Language</span><span style="color: blue;">=</span><span style="color: blue;">"C#"</span> <span style="color: red;">Class</span><span style="color: blue;">=</span><span style="color: blue;">"proxy"</span> <span style="background: yellow;">%></span>
<span style="color: green;">/*</span>
<span style="color: green;"> This proxy page does not have any security checks. It is highly recommended</span>
<span style="color: green;"> that a user deploying this proxy page on their web server, add appropriate</span>
<span style="color: green;"> security checks, for example checking request path, username/password, target</span>
<span style="color: green;"> url, etc.</span>
<span style="color: green;">*/</span>
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Drawing;
<span style="color: blue;">using</span> System.IO;
<span style="color: blue;">using</span> System.Web;
<span style="color: blue;">using</span> System.Collections.Generic;
<span style="color: blue;">using</span> System.Text;
<span style="color: blue;">using</span> System.Xml.Serialization;
<span style="color: blue;">using</span> System.Web.Caching;
<span style="color: blue;">using</span> System.Net;
<span style="color: blue;">using</span> System.Security.Cryptography.X509Certificates;
<span style="color: blue;">using</span> System.Security.Cryptography;
<span style="color: blue;">using</span> OAuth.Net.Common;
<span style="color: blue;">using</span> OAuth.Net.Components;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Forwards requests to an ArcGIS Server REST resource.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">proxy</span> : <span style="color: #2b91af;">IHttpHandler</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">void</span> ProcessRequest(<span style="color: #2b91af;">HttpContext</span> context)
{
System.Collections.Specialized.<span style="color: #2b91af;">NameValueCollection</span> queryString = context.Request.QueryString;
<span style="color: blue;">string</span> layerName = queryString[<span style="color: #a31515;">"layerName"</span>];
<span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">string</span>> dataConfig = <span style="color: blue;">this</span>.getDataFromConfigFile(layerName);
<span style="color: blue;">if</span> (<span style="color: #2b91af;">Convert</span>.ToBoolean(dataConfig[<span style="color: #a31515;">"oauth"</span>]))
{
ISigningProvider SigningProvider = <span style="color: blue;">new</span> HmacSha1SigningProvider();
<span style="color: blue;">var</span> param = <span style="color: blue;">new</span> OAuthParameters()
{
ConsumerKey = queryString[<span style="color: #a31515;">"oauth_consumer_key"</span>],
SignatureMethod = queryString[<span style="color: #a31515;">"oauth_signature_method"</span>],
Version = queryString[<span style="color: #a31515;">"oauth_version"</span>],
Nonce = queryString[<span style="color: #a31515;">"oauth_nonce"</span>],
Timestamp = queryString[<span style="color: #a31515;">"oauth_timestamp"</span>]
};
param.AdditionalParameters.Add(<span style="color: #a31515;">"oauth_body_hash"</span>, <span style="color: #2b91af;">HttpUtility</span>.HtmlDecode(queryString[<span style="color: #a31515;">"oauth_body_hash"</span>]));
<span style="color: blue;">foreach</span> (<span style="color: blue;">string</span> s <span style="color: blue;">in</span> queryString.Keys)
{
<span style="color: blue;">if</span> (!s.StartsWith(<span style="color: #a31515;">"oauth_"</span>))
{
param.AdditionalParameters.Add(s, queryString[s]);
}
}
<span style="color: blue;">var</span> signatureBase = SignatureBase.Create(<span style="color: #2b91af;">WebRequestMethods</span>.<span style="color: #2b91af;">Http</span>.Get, <span style="color: blue;">new</span> <span style="color: #2b91af;">Uri</span>(context.Request.Url.GetLeftPart(<span style="color: #2b91af;">UriPartial</span>.Path)), param);
<span style="color: blue;">if</span> (!SigningProvider.CheckSignature(signatureBase, <span style="color: #2b91af;">HttpUtility</span>.HtmlDecode(queryString[<span style="color: #a31515;">"oauth_signature"</span>]), dataConfig[<span style="color: #a31515;">"oauthConsumerSecret"</span>], <span style="color: blue;">null</span>))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"Unauthorized"</span>);
}
}
<span style="color: #2b91af;">HttpResponse</span> response = context.Response;
System.Collections.Specialized.<span style="color: #2b91af;">NameValueCollection</span> nvc = <span style="color: blue;">new</span> System.Collections.Specialized.<span style="color: #2b91af;">NameValueCollection</span>();
<span style="color: blue;">foreach</span> (<span style="color: blue;">string</span> s <span style="color: blue;">in</span> queryString.Keys)
{
<span style="color: blue;">if</span> (!s.StartsWith(<span style="color: #a31515;">"oauth_"</span>))
{
nvc.Add(s, queryString[s]);
}
}
<span style="color: green;">// Get token for ags service, and url operation soe and append to the request</span>
<span style="color: blue;">if</span> (!<span style="color: blue;">string</span>.IsNullOrEmpty(dataConfig[<span style="color: #a31515;">"token"</span>]))
{
nvc.Add(<span style="color: #a31515;">"token"</span>, dataConfig[<span style="color: #a31515;">"token"</span>]);
}
nvc.Add(<span style="color: #a31515;">"f"</span>, <span style="color: #a31515;">"json"</span>);
System.Net.<span style="color: #2b91af;">WebRequest</span> req = System.Net.<span style="color: #2b91af;">WebRequest</span>.Create(<span style="color: blue;">new</span> <span style="color: #2b91af;">Uri</span>(dataConfig[<span style="color: #a31515;">"urlOperation"</span>] + ToQueryString(nvc)));
req.Method = context.Request.HttpMethod;
<span style="color: green;">// Set body of request for POST requests</span>
<span style="color: blue;">if</span> (context.Request.InputStream.Length > 0)
{
<span style="color: blue;">byte</span>[] bytes = <span style="color: blue;">new</span> <span style="color: blue;">byte</span>[context.Request.InputStream.Length];
context.Request.InputStream.Read(bytes, 0, (<span style="color: blue;">int</span>)context.Request.InputStream.Length);
req.ContentLength = bytes.Length;
req.ContentType = <span style="color: #a31515;">"application/x-www-form-urlencoded"</span>;
<span style="color: blue;">using</span> (<span style="color: #2b91af;">Stream</span> outputStream = req.GetRequestStream())
{
outputStream.Write(bytes, 0, bytes.Length);
}
}
<span style="color: green;">// Send the request to the server</span>
System.Net.<span style="color: #2b91af;">WebResponse</span> serverResponse = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
serverResponse = req.GetResponse();
}
<span style="color: blue;">catch</span> (System.Net.<span style="color: #2b91af;">WebException</span> webExc)
{
response.StatusCode = 500;
response.StatusDescription = webExc.Status.ToString();
response.Write(webExc.Response);
response.End();
<span style="color: blue;">return</span>;
}
<span style="color: green;">// Set up the response to the client</span>
<span style="color: blue;">if</span> (serverResponse != <span style="color: blue;">null</span>)
{
response.ContentType = serverResponse.ContentType;
<span style="color: blue;">using</span> (<span style="color: #2b91af;">Stream</span> byteStream = serverResponse.GetResponseStream())
{
<span style="color: green;">// Text response</span>
<span style="color: blue;">if</span> (serverResponse.ContentType.Contains(<span style="color: #a31515;">"text"</span>))
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">StreamReader</span> sr = <span style="color: blue;">new</span> <span style="color: #2b91af;">StreamReader</span>(byteStream))
{
<span style="color: blue;">string</span> strResponse = sr.ReadToEnd();
response.Write(strResponse);
}
}
<span style="color: blue;">else</span>
{
<span style="color: green;">// Binary response (image, lyr file, other binary file)</span>
<span style="color: #2b91af;">BinaryReader</span> br = <span style="color: blue;">new</span> <span style="color: #2b91af;">BinaryReader</span>(byteStream);
<span style="color: blue;">byte</span>[] outb = br.ReadBytes((<span style="color: blue;">int</span>)serverResponse.ContentLength);
br.Close();
<span style="color: green;">// Tell client not to cache the image since it's dynamic</span>
response.CacheControl = <span style="color: #a31515;">"no-cache"</span>;
<span style="color: green;">// Send the image to the client</span>
<span style="color: green;">// (Note: if large images/files sent, could modify this to send in chunks)</span>
response.OutputStream.Write(outb, 0, outb.Length);
}
serverResponse.Close();
}
}
response.End();
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> IsReusable
{
<span style="color: blue;">get</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> ToQueryString(System.Collections.Specialized.<span style="color: #2b91af;">NameValueCollection</span> nvc)
{
<span style="color: blue;">return</span> <span style="color: #a31515;">"?"</span> + <span style="color: blue;">string</span>.Join(<span style="color: #a31515;">"&"</span>, <span style="color: #2b91af;">Array</span>.ConvertAll(nvc.AllKeys, key => <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"{0}={1}"</span>, key, nvc[key])));
}
<span style="color: green;">// Gets the token and urlOperation for a server URL from a configuration file</span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>,<span style="color: blue;">string</span>> getDataFromConfigFile(<span style="color: blue;">string</span> layerName)
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">LayarConfig</span> config = <span style="color: #2b91af;">LayarConfig</span>.GetCurrentConfig();
<span style="color: blue;">if</span> (config != <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>,<span style="color: blue;">string</span>> dct = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>,<span style="color: blue;">string</span>>();
dct.Add(<span style="color: #a31515;">"token"</span>,config.GetToken(layerName));
dct.Add(<span style="color: #a31515;">"urlOperation"</span>,config.GetUrlOperation(layerName));
dct.Add(<span style="color: #a31515;">"oauth"</span>, config.GetOAuth(layerName).ToString());
dct.Add(<span style="color: #a31515;">"oauthConsumerSecret"</span>, config.GetOAuthConsumerSecret(layerName));
<span style="color: blue;">return</span> dct;
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ApplicationException</span>(<span style="color: #a31515;">"Layar.config file does not exist at application root, or is not readable."</span>);
}
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">InvalidOperationException</span>)
{
<span style="color: #2b91af;">HttpResponse</span> response = <span style="color: #2b91af;">HttpContext</span>.Current.Response;
response.StatusCode = (<span style="color: blue;">int</span>)System.Net.<span style="color: #2b91af;">HttpStatusCode</span>.Forbidden;
response.End();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> e)
{
<span style="color: blue;">if</span> (e <span style="color: blue;">is</span> <span style="color: #2b91af;">ApplicationException</span>)
{
<span style="color: blue;">throw</span> e;
}
}
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">Exception</span>();
}
}
[<span style="color: #2b91af;">XmlRoot</span>(<span style="color: #a31515;">"LayarConfig"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">LayarConfig</span>
{
<span style="color: blue;"> #region</span> Static Members
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">object</span> _lockobject = <span style="color: blue;">new</span> <span style="color: blue;">object</span>();
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">LayarConfig</span> LoadLayarConfig(<span style="color: blue;">string</span> fileName)
{
<span style="color: #2b91af;">LayarConfig</span> config = <span style="color: blue;">null</span>;
<span style="color: blue;">lock</span> (_lockobject)
{
<span style="color: blue;">if</span> (System.IO.<span style="color: #2b91af;">File</span>.Exists(fileName))
{
<span style="color: #2b91af;">XmlSerializer</span> reader = <span style="color: blue;">new</span> <span style="color: #2b91af;">XmlSerializer</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">LayarConfig</span>));
<span style="color: blue;">using</span> (System.IO.<span style="color: #2b91af;">StreamReader</span> file = <span style="color: blue;">new</span> System.IO.<span style="color: #2b91af;">StreamReader</span>(fileName))
{
config = (<span style="color: #2b91af;">LayarConfig</span>)reader.Deserialize(file);
}
}
}
<span style="color: blue;">return</span> config;
}
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">LayarConfig</span> GetCurrentConfig()
{
<span style="color: #2b91af;">LayarConfig</span> config = <span style="color: #2b91af;">HttpRuntime</span>.Cache[<span style="color: #a31515;">"layarConfig"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">LayarConfig</span>;
<span style="color: blue;">if</span> (config == <span style="color: blue;">null</span>)
{
<span style="color: blue;">string</span> fileName = GetFilename(<span style="color: #2b91af;">HttpContext</span>.Current);
config = LoadLayarConfig(fileName);
<span style="color: blue;">if</span> (config != <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">CacheDependency</span> dep = <span style="color: blue;">new</span> <span style="color: #2b91af;">CacheDependency</span>(fileName);
<span style="color: #2b91af;">HttpRuntime</span>.Cache.Insert(<span style="color: #a31515;">"layarConfig"</span>, config, dep);
}
}
<span style="color: blue;">return</span> config;
}
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> GetFilename(<span style="color: #2b91af;">HttpContext</span> context)
{
<span style="color: blue;">return</span> context.Server.MapPath(<span style="color: #a31515;">"~/layar.config"</span>);
}
<span style="color: blue;"> #endregion</span>
<span style="color: #2b91af;">ServerUrl</span>[] serverUrls;
[<span style="color: #2b91af;">XmlArray</span>(<span style="color: #a31515;">"serverUrls"</span>)]
[<span style="color: #2b91af;">XmlArrayItem</span>(<span style="color: #a31515;">"serverUrl"</span>)]
<span style="color: blue;">public</span> <span style="color: #2b91af;">ServerUrl</span>[] ServerUrls
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: blue;">this</span>.serverUrls; }
<span style="color: blue;">set</span> { <span style="color: blue;">this</span>.serverUrls = <span style="color: blue;">value</span>; }
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> GetUrlOperation(<span style="color: blue;">string</span> layerName)
{
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">ServerUrl</span> su <span style="color: blue;">in</span> serverUrls)
{
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.Compare(layerName, su.Layername, <span style="color: blue;">true</span>) == 1)
{
<span style="color: blue;">return</span> su.UrlOperation;
}
}
<span style="color: blue;">return</span> <span style="color: blue;">string</span>.Empty;
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> GetOAuthConsumerSecret(<span style="color: blue;">string</span> layerName)
{
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">ServerUrl</span> su <span style="color: blue;">in</span> serverUrls)
{
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.Compare(layerName, su.Layername, <span style="color: blue;">true</span>) == 1)
{
<span style="color: blue;">return</span> su.OAuthConsumerSecret;
}
}
<span style="color: blue;">return</span> <span style="color: blue;">string</span>.Empty;
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> GetOAuth(<span style="color: blue;">string</span> layerName)
{
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">ServerUrl</span> su <span style="color: blue;">in</span> serverUrls)
{
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.Compare(layerName, su.Layername, <span style="color: blue;">true</span>) == 1)
{
<span style="color: blue;">return</span> su.OAuth;
}
}
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> GetToken(<span style="color: blue;">string</span> layerName)
{
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">ServerUrl</span> su <span style="color: blue;">in</span> serverUrls)
{
<span style="color: blue;">if</span> (<span style="color: blue;">string</span>.Compare(layerName, su.Layername, <span style="color: blue;">true</span>) == 1 && su.DynamicToken)
{
<span style="color: green;">// Code to dynamically get the token</span>
<span style="color: blue;">string</span> tokenService = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"https://{0}/{1}/tokens?request=getToken&username={2}&password={3}&expiration=30"</span>, su.Host, su.Instance, su.UserName, su.Password);
<span style="color: blue;">string</span> token;
<span style="color: green;">// This script is added to force the application to certify the SSL script (if for example you have a self certificate on server)</span>
System.Net.<span style="color: #2b91af;">ServicePointManager</span>.ServerCertificateValidationCallback += <span style="color: blue;">delegate</span>(<span style="color: blue;">object</span> sender, System.Security.Cryptography.X509Certificates.<span style="color: #2b91af;">X509Certificate</span> certificate, System.Security.Cryptography.X509Certificates.<span style="color: #2b91af;">X509Chain</span> chain, System.Net.Security.<span style="color: #2b91af;">SslPolicyErrors</span> sslPolicyErrors)
{
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
};
System.Net.<span style="color: #2b91af;">WebRequest</span> tokenRequest = System.Net.<span style="color: #2b91af;">WebRequest</span>.Create(tokenService);
System.Net.<span style="color: #2b91af;">WebResponse</span> tokenResponse = tokenRequest.GetResponse();
System.IO.<span style="color: #2b91af;">Stream</span> responseStream = tokenResponse.GetResponseStream();
System.IO.<span style="color: #2b91af;">StreamReader</span> readStream = <span style="color: blue;">new</span> System.IO.<span style="color: #2b91af;">StreamReader</span>(responseStream);
token = readStream.ReadToEnd();
<span style="color: blue;">return</span> token;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (<span style="color: blue;">string</span>.Compare(layerName, su.Layername, <span style="color: blue;">true</span>) == 1)
{
<span style="color: blue;">return</span> su.Token;
}
}
<span style="color: blue;">return</span> <span style="color: blue;">string</span>.Empty;
}
}
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">ServerUrl</span>
{
<span style="color: blue;">string</span> urlOperation;
<span style="color: blue;">string</span> token;
<span style="color: blue;">bool</span> dynamicToken;
<span style="color: blue;">string</span> userName;
<span style="color: blue;">string</span> host;
<span style="color: blue;">string</span> password;
<span style="color: blue;">string</span> instance;
<span style="color: blue;">string</span> layername;
<span style="color: blue;">string</span> oauthConsumerSecret;
<span style="color: blue;">bool</span> oauth;
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"layername"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Layername
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> layername; }
<span style="color: blue;">set</span> { layername = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"urlOperation"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> UrlOperation
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> urlOperation; }
<span style="color: blue;">set</span> { urlOperation = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"token"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Token
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> token; }
<span style="color: blue;">set</span> { token = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"dynamicToken"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> DynamicToken
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> dynamicToken; }
<span style="color: blue;">set</span> { dynamicToken = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"host"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Host
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> host; }
<span style="color: blue;">set</span> { host = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"instance"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Instance
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> instance; }
<span style="color: blue;">set</span> { instance = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"userName"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> UserName
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> userName; }
<span style="color: blue;">set</span> { userName = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"password"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Password
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> password; }
<span style="color: blue;">set</span> { password = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"oauthConsumerSecret"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> OAuthConsumerSecret
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> oauthConsumerSecret; }
<span style="color: blue;">set</span> { oauthConsumerSecret = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">XmlAttribute</span>(<span style="color: #a31515;">"oauth"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> OAuth
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> oauth; }
<span style="color: blue;">set</span> { oauth = <span style="color: blue;">value</span>; }
}
}</pre>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
<div style="background: white; color: black; font-family: Consolas; font-size: 13px;">
</div>
Ora non ci resta che registrarci sul sito di Layar e pubblicare il nostro url endpoint:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgecgD0oYpfo0WpzAOhz3At50YzK_ECYdnQf_n_raLmxbmdxmUdiUTYcw3cg8QI1Ge5zEqNB4LncgLOzHOMQGMpI4o_sTWgswhMQIM9TZT-EzIj9uZrJVkq1kKmBwI6FOhZ0opjVUDO74zc/s1600/Layar2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgecgD0oYpfo0WpzAOhz3At50YzK_ECYdnQf_n_raLmxbmdxmUdiUTYcw3cg8QI1Ge5zEqNB4LncgLOzHOMQGMpI4o_sTWgswhMQIM9TZT-EzIj9uZrJVkq1kKmBwI6FOhZ0opjVUDO74zc/s1600/Layar2.png" /></a></div>
<br />
In <strong>Additional settings</strong> avete la possibilità gestire il <a href="http://layar.com/documentation/browser/howtos/user-authentication/" target="_blank">flusso di autenticazione</a> degli utenti al proprio layer.<br />
<br />
Prima della pubbicazione abbiamo la possibilità di testarlo sia via web che su mobile loggandoci con il nostro utente nell'app.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0LXsWXl_LZxvJ0Ir178UVTniygnotUumkZMQ7mdNk62dEn9vel-ozo0gviDQWLO4VyeqiQHqBUtgJesGWs02lW9i9UN-Nna1ehFxgNkkbxlSYj6K3PP_APzo5h8fvv6In3-EGg162ju_V/s1600/Layar3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="316" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0LXsWXl_LZxvJ0Ir178UVTniygnotUumkZMQ7mdNk62dEn9vel-ozo0gviDQWLO4VyeqiQHqBUtgJesGWs02lW9i9UN-Nna1ehFxgNkkbxlSYj6K3PP_APzo5h8fvv6In3-EGg162ju_V/s640/Layar3.png" width="640" /></a></div>
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhT5l6u0HJ6jiXYbP-00NxuROWQPQoqZd1Oh-D4xTHFrCUtwIYQ-lCagARllYy3OiE9EyqZMAefGDg0WfhF9RJpH3nwjNGzeOBCuLy4MyqyjC5NBvHLu2VZRy9ROSstCDgNh1ynRMS3ow68/s1600/Layar4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="550" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhT5l6u0HJ6jiXYbP-00NxuROWQPQoqZd1Oh-D4xTHFrCUtwIYQ-lCagARllYy3OiE9EyqZMAefGDg0WfhF9RJpH3nwjNGzeOBCuLy4MyqyjC5NBvHLu2VZRy9ROSstCDgNh1ynRMS3ow68/s640/Layar4.png" width="640" /></a></div>
<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4dvnovvZQFbwcPUTzZvA_G9LSG3vXLhATB8bzcZkU5PxvYInW8UtanSUvp68ObpWDBH_ZE7mcoAmQgGHZZMW7_7Gfi4685uKcwIaFtnMuZAAguYG_2E1wmOfbqGmLu_NPtFzu5PKzHvh_/s1600/layar5.png" imageanchor="1"><img border="0" height="424" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4dvnovvZQFbwcPUTzZvA_G9LSG3vXLhATB8bzcZkU5PxvYInW8UtanSUvp68ObpWDBH_ZE7mcoAmQgGHZZMW7_7Gfi4685uKcwIaFtnMuZAAguYG_2E1wmOfbqGmLu_NPtFzu5PKzHvh_/s640/layar5.png" width="640" /></a></div>
Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-9119029881884726252013-02-25T23:06:00.003+01:002013-07-31T19:57:35.008+02:00Alziamo il livello: 3D surface!In ArcGIS è disponibile la toolbar 3D Analyst, sia in ArcMap che in ArcScene. Una volta abilitata l'estensione 3D Analyst, abbiamo a disposizione strumenti che ci consentono di operare su superfici 3D. Gli strumenti lavorano con <a href="http://resources.arcgis.com/en/help/main/10.1/0060/006000000001000000.htm">TIN</a>, <a href="http://resources.arcgis.com/en/help/main/10.1/009t/009t00000002000000.htm">raster</a>, <a href="http://resources.arcgis.com/en/help/main/10.1/005v/005v00000002000000.htm">terrain dataset</a> o <a href="http://resources.arcgis.com/en/help/main/10.1/index.html#//015w00000057000000">LAS dataset</a> e forniscono feedback in tempo reale sui punti digitalizzati sulla superficie. Comunque per dataset terrain e LAS sono presenti alcune restrizioni nell'utilizzo dei tool interattivi.<br />
Gli strumenti interattivi sono:<br />
<ul>
<li>Create Countours</li>
<li>Create Steepest Path</li>
<li>Create Line of Sight</li>
<li>Interpolate Point</li>
<li>Interpolate Line</li>
<li>Interpolate Polygon</li>
<li>Create Profiles</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgX3oFBLiWA7tKMRdK6UU1T1d3Qd6UiHfoCWDh-83MiF1QKcnA3lbogbDO8pzkA3rY7RgvMad4YkXj4tdPDUtSvztwRZVLqyrzPn0H0uvpvlVex684yU_vJoWakFkmp7fn_7StTQzXGQYR/s1600/GUID-10ECA4BE-D26C-4ED7-B650-7D76673D2DA1-web.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgX3oFBLiWA7tKMRdK6UU1T1d3Qd6UiHfoCWDh-83MiF1QKcnA3lbogbDO8pzkA3rY7RgvMad4YkXj4tdPDUtSvztwRZVLqyrzPn0H0uvpvlVex684yU_vJoWakFkmp7fn_7StTQzXGQYR/s400/GUID-10ECA4BE-D26C-4ED7-B650-7D76673D2DA1-web.png" width="400" /></a></div>
<br />
Nel menu a discesa della toolbar 3D Analyst sono disponibili delle opzioni di visualizzazione e interpolazione per la creazione dei profili. Per maggiori dettagli sui tool interattivi 3D Analyst seguire il seguente <a href="http://resources.arcgis.com/en/help/main/10.1/00q8/00q8000000v1000000.htm" target="_blank">link</a>.<br />
<br />
Se volessimo utilizzare le stesse funzionalità come servizio possiamo servirci di metodi che gestiscono le surface che, nel caso specifico, sono esposti dell' interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/002500000877000000.htm" target="_blank">ISurface</a>. L'interfaccia è nella libreria Geodatabase degli ArcObjects.<br />
<br />
Ad esempio, se dovessimo creare una LOS (Line of Sight) utilizziamo il metodo <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/00250000087w000000.htm" target="_blank">GetLineOfSight</a>. Va sottolineato che per questo metodo in .NET è consigliato comunque usare <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/002500000397000000.htm" target="_blank">IGeoDatabaseBridge2.GetLineOfSight</a> che fornisce la stessa funzionalità ma con interoperabilità sicura. Ricordarsi anche che la classe che implementa IGeoDatabaseBrigde2, <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000000nq000000.htm" target="_blank">GeodatabaseHelper</a> è singleton e pertanto occorre utilizzare l'activator. Se analizziamo nel dettaglio il metodo, osserviamo che è richiesta la <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/002500000877000000.htm" target="_blank">ISurface</a>, il punto dell'osservatore, il punto osservato (target), se applicare la curvatura terrestre (utilizzabile solo se la surface ha un sistema di coordinate proiettate con definita l'unità di misura della Z), se considerare la <a href="http://it.wikipedia.org/wiki/Rifrazione_atmosferica" target="_blank">rifrazione atmosferica</a> (utilizzabile solo se la surface ha un sistema di coordinate proiettate con definita l'unità di misura della Z) e il fattore di rifrazione (se il valore non viene fornito il valore predefinito è 0.13).<br />
La formula utilizzata per la correzione della rifrazione atmosferica è:<br />
<br />
<div style="text-align: center;">
<pre class="equation"><span style="font-size: medium;">Z = Z<sub>0</sub> + D<sup>2</sup>(R - 1) ÷ d</span></pre>
</div>
<br />
<pre class="equation">Z = Valore di quota corretto dopo aver compensato l'influenza della rifrazione atmosferica</pre>
<pre class="equation">Z<sub>0</sub> = Quota dell'osservatore
D = distanza planimetrica tra l'osservatore e l'osservato</pre>
<pre class="equation">d = diametro della terra (12740 Km)</pre>
<pre class="equation">R = coefficiente di rifrazione della luce (default 0.13)</pre>
<pre class="equation"> </pre>
<pre class="equation"></pre>
Il metodo restituisce le linee visibili e le linee invisibili mediante singole polyline dall'osservatore al target e se il target è visibile. Le linee hanno i valori Z interpolati sulla superficie. Chiaramente è possibile avere anche una delle due polilinee nulle e quindi visibilità completa o meno.<br />
Il metodo restituisce anche il punto di obstruction ovvero se il target non è visibile, il primo punto di intersezione dall'osservatore verso il target tra la superficie e la LOS che è utilizzata. Anche qui, se il target è visibile dall'osservatore, il punto di obstruction sarà nullo.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-_9da4yRE73tAz4dA6xG9cHLq8TVhtKfa2OOOvdYTB63BsBpx3t9e72UhtJMkP1OGj9LuTuokTiH-34_8hw014_zBcF7ym4de5-WvkrRqwPfEOImv0oqzYLy6kDVDaSgYy9m-NeqZr8Fd/s1600/los.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="161" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-_9da4yRE73tAz4dA6xG9cHLq8TVhtKfa2OOOvdYTB63BsBpx3t9e72UhtJMkP1OGj9LuTuokTiH-34_8hw014_zBcF7ym4de5-WvkrRqwPfEOImv0oqzYLy6kDVDaSgYy9m-NeqZr8Fd/s400/los.png" width="400" /></a></div>
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Method for implementing REST operation "GetLineOfSight"'s functionality.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"boundVariables"</span><span style="color: grey;">></span><span style="color: green;">object boundVariables</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationInput"</span><span style="color: grey;">></span><span style="color: green;">object operationInput</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">object outputFormat</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">object requestProperties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">object responseProperties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">String JSON representation of output</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">byte</span>[] GetLineOfSightOperHandler(<span style="color: #2b91af;">NameValueCollection</span> boundVariables, <span style="color: #2b91af;">JsonObject</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"application/json\"}"</span>;
<span style="color: blue;">int</span> layerID = System.<span style="color: #2b91af;">Convert</span>.ToInt32(boundVariables[<span style="color: #a31515;">"SurfaceLayersID"</span>], <span style="color: #2b91af;">CultureInfo</span>.InvariantCulture);
<span style="color: #2b91af;">AnalysisSurface</span> analysisSurface = <span style="color: blue;">this</span>.GetSurfaceLayerInfo(layerID).GetAnalysisSurface();
<span style="color: green;">// offsetObserver</span>
<span style="color: blue;">double</span>? offsetObserver;
operationInput.TryGetAsDouble(<span style="color: #a31515;">"offsetObserver"</span>, <span style="color: blue;">out</span> offsetObserver);
<span style="color: green;">// offsetTarget</span>
<span style="color: blue;">double</span>? offsetTarget;
operationInput.TryGetAsDouble(<span style="color: #a31515;">"offsetTarget"</span>, <span style="color: blue;">out</span> offsetTarget);
<span style="color: #2b91af;">JsonObject</span> jsonLine;
<span style="color: blue;">if</span> (!operationInput.TryGetJsonObject(<span style="color: #a31515;">"geometry"</span>, <span style="color: blue;">out</span> jsonLine))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceUtilityException</span>(<span style="color: #a31515;">"Geometry is wrong!"</span>);
}
<span style="color: #2b91af;">IPolyline</span> polyline = jsonLine.ConvertAnyJsonGeom() <span style="color: blue;">as</span> <span style="color: #2b91af;">IPolyline</span>;
<span style="color: blue;">if</span> (polyline == <span style="color: blue;">null</span>)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceUtilityException</span>(<span style="color: #a31515;">"Geometry is wrong!"</span>);
}
<span style="color: blue;">bool</span>? applyCurvature;
operationInput.TryGetAsBoolean(<span style="color: #a31515;">"applyCurvature"</span>, <span style="color: blue;">out</span> applyCurvature);
<span style="color: blue;">if</span> (!applyCurvature.HasValue)
{
applyCurvature = <span style="color: blue;">false</span>;
}
<span style="color: blue;">bool</span>? applyRefraction;
operationInput.TryGetAsBoolean(<span style="color: #a31515;">"applyRefraction"</span>, <span style="color: blue;">out</span> applyRefraction);
<span style="color: blue;">if</span> (!applyRefraction.HasValue)
{
applyRefraction = <span style="color: blue;">false</span>;
}
<span style="color: blue;">double</span>? refractionFactor;
operationInput.TryGetAsDouble(<span style="color: #a31515;">"refractionFactor"</span>, <span style="color: blue;">out</span> refractionFactor);
<span style="color: blue;">object</span> refractionFactorValue = <span style="color: #2b91af;">Type</span>.Missing;
<span style="color: blue;">if</span> (refractionFactor.HasValue)
{
refractionFactorValue = refractionFactor.Value;
}
<span style="color: #2b91af;">IPoint</span> pointFrom = polyline.FromPoint;
<span style="color: #2b91af;">IPoint</span> pointTo = polyline.ToPoint;
<span style="color: #2b91af;">ISurface</span> surface = analysisSurface.Surface;
pointFrom.Z = surface.GetElevation(pointFrom);
pointTo.Z = surface.GetElevation(pointTo);
<span style="color: blue;">if</span> (surface.IsVoidZ(pointFrom.Z) || surface.IsVoidZ(pointTo.Z))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceUtilityException</span>(<span style="color: #a31515;">"End points line not valid!"</span>);
}
<span style="color: blue;">if</span> (offsetObserver.HasValue)
{
pointFrom.Z += offsetObserver.Value;
}
<span style="color: blue;">if</span> (offsetTarget.HasValue)
{
pointTo.Z += offsetTarget.Value;
}
<span style="color: #2b91af;">IPoint</span> pointObstruction;
<span style="color: #2b91af;">IPolyline</span> visibleLines;
<span style="color: #2b91af;">IPolyline</span> invisibleLines;
<span style="color: blue;">bool</span> isVisible;
<span style="color: green;">// applyCurvature and applyRefraction can be true if the surface has a defined projected coordinate system that includes defined ZUnits. </span>
<span style="color: blue;">try</span>
{
<span style="color: blue;">if</span> (!surface.CanDoCurvature)
{
applyCurvature = <span style="color: blue;">false</span>;
applyRefraction = <span style="color: blue;">false</span>;
}
}
<span style="color: blue;">catch</span>
{
applyCurvature = <span style="color: blue;">false</span>;
applyRefraction = <span style="color: blue;">false</span>;
}
<span style="color: #2b91af;">Type</span> t = <span style="color: #2b91af;">Type</span>.GetTypeFromProgID(<span style="color: #a31515;">"esriGeodatabase.GeoDatabaseHelper"</span>);
System.<span style="color: #2b91af;">Object</span> obj = <span style="color: #2b91af;">Activator</span>.CreateInstance(t);
<span style="color: #2b91af;">IGeoDatabaseBridge2</span> geoDatabaseBridge = obj <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeoDatabaseBridge2</span>;
geoDatabaseBridge.GetLineOfSight(surface, pointFrom, pointTo, <span style="color: blue;">out</span> pointObstruction, <span style="color: blue;">out</span> visibleLines, <span style="color: blue;">out</span> invisibleLines, <span style="color: blue;">out</span> isVisible, applyCurvature.Value, applyRefraction.Value, <span style="color: blue;">ref</span> refractionFactorValue);
<span style="color: #2b91af;">JsonObject</span> result = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
result.AddJsonObject(<span style="color: #a31515;">"pointObstruction"</span>, <span style="color: #2b91af;">Conversion</span>.ToJsonObject(pointObstruction));
result.AddJsonObject(<span style="color: #a31515;">"visibleLines"</span>, <span style="color: #2b91af;">Conversion</span>.ToJsonObject(visibleLines));
result.AddJsonObject(<span style="color: #a31515;">"invisibleLines"</span>, <span style="color: #2b91af;">Conversion</span>.ToJsonObject(invisibleLines));
result.AddBoolean(<span style="color: #a31515;">"isVisible"</span>, isVisible);
<span style="color: blue;">return</span> result.JsonByte();
}</pre>
<br />
Un altro interessante metodo è il <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/00250000088m000000.htm" target="_blank">Locate</a> che permette di individuare l'intersezione tra la surface e il ray. Un <a href="http://en.wikipedia.org/wiki/Ray_(geometry)#Ray" target="_blank">ray</a> ha un end point che è la sua origine e continua indefinitamente nell'altra direzione: la direzione viene fornita mediante un vettore. Come possiamo notare dall'immagine (2° caso) se il punto di intersezione con la surface è contenuto tra i due punti che derminano l'origine e la direzione allora l'intersezione coincide con il punto di obstruction della LOS.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU2TXBiw9l125jt3MHupnPyR-wjKewJWutdAKVNRhMn_DyBFmd_O5416Kdj7b7Et-TTP69suyxXBHT_H3r9hG85H6CAB4NQ33vD81VWEEueGEZRHL1FR-tZZmNC1tDBKHgsc8VLdR5Pz7e/s1600/Locate.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="267" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU2TXBiw9l125jt3MHupnPyR-wjKewJWutdAKVNRhMn_DyBFmd_O5416Kdj7b7Et-TTP69suyxXBHT_H3r9hG85H6CAB4NQ33vD81VWEEueGEZRHL1FR-tZZmNC1tDBKHgsc8VLdR5Pz7e/s400/Locate.png" width="400" /></a></div>
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: grey;"> ///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Method for implementing REST operation "GetLocate"'s functionality.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"boundVariables"</span><span style="color: grey;">></span><span style="color: green;">object boundVariables</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationInput"</span><span style="color: grey;">></span><span style="color: green;">object operationInput</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"outputFormat"</span><span style="color: grey;">></span><span style="color: green;">object outputFormat</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"requestProperties"</span><span style="color: grey;">></span><span style="color: green;">object requestProperties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"responseProperties"</span><span style="color: grey;">></span><span style="color: green;">object responseProperties</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">String JSON representation of output</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">byte</span>[] GetLocateHandler(<span style="color: #2b91af;">NameValueCollection</span> boundVariables, <span style="color: #2b91af;">JsonObject</span> operationInput, <span style="color: blue;">string</span> outputFormat, <span style="color: blue;">string</span> requestProperties, <span style="color: blue;">out</span> <span style="color: blue;">string</span> responseProperties)
{
responseProperties = <span style="color: #a31515;">"{\"Content-Type\" : \"application/json\"}"</span>;
<span style="color: blue;">int</span> layerID = System.<span style="color: #2b91af;">Convert</span>.ToInt32(boundVariables[<span style="color: #a31515;">"SurfaceLayersID"</span>], <span style="color: #2b91af;">CultureInfo</span>.InvariantCulture);
<span style="color: #2b91af;">AnalysisSurface</span> analysisSurface = <span style="color: blue;">this</span>.GetSurfaceLayerInfo(layerID).GetAnalysisSurface();
<span style="color: #2b91af;">JsonObject</span> jsonGeometry;
<span style="color: blue;">if</span> (!operationInput.TryGetJsonObject(<span style="color: #a31515;">"geometry"</span>, <span style="color: blue;">out</span> jsonGeometry))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceUtilityException</span>(<span style="color: #a31515;">"Geometry is wrong!"</span>);
}
<span style="color: #2b91af;">IPolyline</span> polyline = jsonGeometry.ConvertAnyJsonGeom() <span style="color: blue;">as</span> <span style="color: #2b91af;">IPolyline</span>;
<span style="color: blue;">if</span> (polyline == <span style="color: blue;">null</span>)
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceUtilityException</span>(<span style="color: #a31515;">"Geometry is wrong!"</span>);
}
<span style="color: #2b91af;">IPoint</span> pointFrom = polyline.FromPoint;
<span style="color: #2b91af;">IPoint</span> pointTo = polyline.ToPoint;
<span style="color: #2b91af;">ISurface</span> surface = analysisSurface.Surface;
<span style="color: green;">// offsetFromPoint</span>
<span style="color: blue;">double</span>? offsetFromPoint;
<span style="color: blue;">if</span> (operationInput.TryGetAsDouble(<span style="color: #a31515;">"offsetFromPoint"</span>, <span style="color: blue;">out</span> offsetFromPoint) && offsetFromPoint.HasValue && offsetFromPoint != <span style="color: blue;">double</span>.NaN)
{
pointFrom.Z = surface.GetElevation(pointFrom);
pointFrom.Z += offsetFromPoint.Value;
}
<span style="color: blue;">if</span> (surface.IsVoidZ(pointFrom.Z))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceUtilityException</span>(<span style="color: #a31515;">"Start point line not valid!"</span>);
}
<span style="color: green;">// offsetToPoint</span>
<span style="color: blue;">double</span>? offsetToPoint;
<span style="color: blue;">if</span> (operationInput.TryGetAsDouble(<span style="color: #a31515;">"offsetToPoint"</span>, <span style="color: blue;">out</span> offsetToPoint) && offsetToPoint.HasValue && offsetToPoint != <span style="color: blue;">double</span>.NaN)
{
pointTo.Z = surface.GetElevation(pointTo);
pointTo.Z += offsetToPoint.Value;
}
<span style="color: blue;">if</span> (surface.IsVoidZ(pointTo.Z))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceUtilityException</span>(<span style="color: #a31515;">"End point line not valid!"</span>);
}
<span style="color: green;">// hint</span>
<span style="color: blue;">long</span>? hint;
operationInput.TryGetAsLong(<span style="color: #a31515;">"hint"</span>, <span style="color: blue;">out</span> hint);
<span style="color: blue;">int</span> hintValue = 0;
<span style="color: blue;">if</span> (operationInput.TryGetAsLong(<span style="color: #a31515;">"hint"</span>, <span style="color: blue;">out</span> hint) && hint.HasValue)
{
hintValue = (<span style="color: blue;">int</span>)hint.Value;
}
<span style="color: #2b91af;">IRay</span> ray = <span style="color: blue;">new</span> <span style="color: #2b91af;">RayClass</span>();
ray.Origin = pointFrom;
ray.Vector = <span style="color: #2b91af;">GeometryUtility</span>.ConstructVector3D(pointTo.X - pointFrom.X, pointTo.Y - pointFrom.Y, pointTo.Z - pointFrom.Z);
<span style="color: #2b91af;">IPoint</span> point = surface.Locate(ray, hintValue);
<span style="color: #2b91af;">JsonObject</span> result = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
result.AddJsonObject(<span style="color: #a31515;">"geometry"</span>, <span style="color: #2b91af;">Conversion</span>.ToJsonObject(point, <span style="color: blue;">true</span>));
<span style="color: blue;">return</span> result.JsonByte();
}</pre>
<br />
<br />
<br />
In <a href="http://resources.arcgis.com/en/communities/runtime-wpf/" target="_blank">ArcGIS Runtime for WPF</a> possiamo richiamare la nostra SOE ed invocare le operazioni in modalità asincrona utilizzando <a href="http://msdn.microsoft.com/en-us/library/vstudio/hh156528.aspx" target="_blank">await</a> e <a href="http://msdn.microsoft.com/en-us/library/vstudio/hh156513.aspx" target="_blank">async</a>:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Class Surface SOE</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">internal</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">SurfaceSOE</span>
{
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> soe name</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> soeName;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> url map service soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">Uri</span> mapServiceUri;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> resource index soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">int</span> resourceIndex;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Initializes a new instance of the </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"SurfaceSOE"</span><span style="color: grey;">/></span><span style="color: green;"> class</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"mapServiceUrl"</span><span style="color: grey;">></span><span style="color: green;">url of map service</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"soeName"</span><span style="color: grey;">></span><span style="color: green;">soe name</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"resourceIndex"</span><span style="color: grey;">></span><span style="color: green;">index of resource</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> SurfaceSOE(<span style="color: blue;">string</span> mapServiceUrl, <span style="color: blue;">string</span> soeName, <span style="color: blue;">int</span> resourceIndex)
{
<span style="color: blue;">this</span>.soeName = soeName;
<span style="color: blue;">this</span>.mapServiceUri = <span style="color: blue;">new</span> <span style="color: #2b91af;">Uri</span>(mapServiceUrl);
<span style="color: blue;">this</span>.resourceIndex = resourceIndex;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Prevents a default instance of the </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"SurfaceSOE"</span><span style="color: grey;">/></span><span style="color: green;"> class from being created.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> SurfaceSOE()
{
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> delegate Operation Result Handler</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"jsonResponse"</span><span style="color: grey;">></span><span style="color: green;">response json</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"source"</span><span style="color: grey;">></span><span style="color: green;">object source</span><span style="color: grey;"></param></span>
<span style="color: blue;">private</span> <span style="color: blue;">delegate</span> <span style="color: blue;">void</span> <span style="color: #2b91af;">OperationResultHandler</span>(<span style="color: blue;">string</span> jsonResponse, <span style="color: blue;">object</span> source);
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> delegate Get Line Of Sight Response Event</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">event</span> <span style="color: #2b91af;">EventHandler</span> GetLineOfSightResponseEvent;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> enumerator of Operation in soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">enum</span> <span style="color: #2b91af;">OperationName</span>
{
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> operation Line of Sight</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
GetLineOfSight
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> validate if soe is online</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">true is online</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">async</span> <span style="color: #2b91af;">Task</span><<span style="color: blue;">bool</span>> Validate()
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">Uri</span> requestUri = <span style="color: blue;">new</span> <span style="color: #2b91af;">Uri</span>(<span style="color: blue;">this</span>.mapServiceUri, <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"exts/{0}/surfaceLayers/{1}?f=json"</span>, <span style="color: blue;">this</span>.soeName, <span style="color: blue;">this</span>.resourceIndex));
<span style="color: blue;">string</span> jsonSOEInfo = <span style="color: blue;">await</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">WebClient</span>().DownloadStringTaskAsync(requestUri);
<span style="color: #2b91af;">JavaScriptSerializer</span> serializer = <span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptSerializer</span>();
serializer.RegisterConverters(<span style="color: blue;">new</span> <span style="color: #2b91af;">JavaScriptConverter</span>[] { <span style="color: blue;">new</span> <span style="color: #2b91af;">DynamicJsonConverter</span>() });
<span style="color: blue;">dynamic</span> infoSOE = serializer.Deserialize(jsonSOEInfo, <span style="color: blue;">typeof</span>(<span style="color: blue;">object</span>)) <span style="color: blue;">as</span> <span style="color: blue;">dynamic</span>;
<span style="color: blue;">var</span> x = infoSOE.id;
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> operation Line of Sight</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"line"</span><span style="color: grey;">></span><span style="color: green;">geometry line</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"offsetObserver"</span><span style="color: grey;">></span><span style="color: green;">offset Observer</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"offsetTarget"</span><span style="color: grey;">></span><span style="color: green;">offset Target</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">async</span> <span style="color: blue;">void</span> GetLineOfSight(<span style="color: #2b91af;">Polyline</span> line, <span style="color: blue;">double</span> offsetObserver, <span style="color: blue;">double</span> offsetTarget)
{
<span style="color: blue;">string</span> operationParams = <span style="color: blue;">string</span>.Format(System.Globalization.<span style="color: #2b91af;">CultureInfo</span>.InvariantCulture, <span style="color: #a31515;">"geometry={0}&offsetObserver={1}&offsetTarget={2}&f=json"</span>, line.ToJson(), offsetObserver, offsetTarget);
<span style="color: blue;">string</span> jsonResponse = <span style="color: blue;">await</span> <span style="color: blue;">this</span>.InvokeOperation(<span style="color: #a31515;">"GetLineOfSight"</span>, operationParams);
<span style="color: #2b91af;">GetLineOfSightResponse</span> response = <span style="color: blue;">new</span> <span style="color: #2b91af;">GetLineOfSightResponse</span>(jsonResponse);
<span style="color: blue;">if</span> (<span style="color: blue;">this</span>.GetLineOfSightResponseEvent != <span style="color: blue;">null</span>)
{
<span style="color: blue;">this</span>.GetLineOfSightResponseEvent(<span style="color: blue;">this</span>, response);
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> invoke of operation</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationName"</span><span style="color: grey;">></span><span style="color: green;">name of operation</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"operationParameters"</span><span style="color: grey;">></span><span style="color: green;">parameters of operation</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">response of operation</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">async</span> <span style="color: #2b91af;">Task</span><<span style="color: blue;">string</span>> InvokeOperation(<span style="color: blue;">string</span> operationName, <span style="color: blue;">string</span> operationParameters)
{
<span style="color: #2b91af;">Uri</span> requestUri = <span style="color: blue;">new</span> <span style="color: #2b91af;">Uri</span>(<span style="color: blue;">this</span>.mapServiceUri, <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"exts/{0}/surfaceLayers/{1}/{2}?{3}"</span>, <span style="color: blue;">this</span>.soeName, <span style="color: blue;">this</span>.resourceIndex, operationName, operationParameters));
<span style="color: blue;">return</span> <span style="color: blue;">await</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">WebClient</span>().DownloadStringTaskAsync(requestUri);
}</pre>
<br />
<br />
MainWindows.xaml.cs
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> class MainWindow</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">partial</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">MainWindow</span> : <span style="color: #2b91af;">Window</span>
{
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> url surface soe mapserver</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> surfaceSoeUrl = <span style="color: #a31515;">"http://sit.sistemigis.it/sit/rest/services/Demo/Surface/MapServer/"</span>;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> name soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> surfaceSoeName = <span style="color: #a31515;">"SurfaceUtility"</span>;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> index of surface resource</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: blue;">int</span> surfaceResourceIndex = 0;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> surface soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">SurfaceSOE</span> surfaceSOE;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> current operation</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">SurfaceSOE</span>.<span style="color: #2b91af;">OperationName</span> currentOperation;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> draw object</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">Draw</span> drawObject;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> current symbol</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: #2b91af;">Symbol</span> currentSymbol;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Initializes a new instance of the </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"MainWindow"</span><span style="color: grey;">/></span><span style="color: green;"> class</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> MainWindow()
{
<span style="color: green;">// License setting and ArcGIS Runtime initialization is done in Application.xaml.cs.</span>
<span style="color: blue;">this</span>.InitializeComponent();
<span style="color: blue;">this</span>.InitializeSOE();
<span style="color: blue;">this</span>.drawObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">Draw</span>(_map)
{
LineSymbol = LayoutRoot.Resources[<span style="color: #a31515;">"BlueLineSymbol"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">LineSymbol</span>
};
<span style="color: blue;">this</span>.drawObject.DrawBegin += <span style="color: blue;">this</span>.MyDrawObject_OnDrawBegin;
<span style="color: blue;">this</span>.drawObject.DrawComplete += <span style="color: blue;">this</span>.MyDrawObject_OnDrawComplete;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> event OnDrawBegin</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"sender"</span><span style="color: grey;">></span><span style="color: green;">object sender</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"args"</span><span style="color: grey;">></span><span style="color: green;">object args</span><span style="color: grey;"></param></span>
<span style="color: blue;">private</span> <span style="color: blue;">void</span> MyDrawObject_OnDrawBegin(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> args)
{
<span style="color: #2b91af;">GraphicsLayer</span> graphicsLayer = _map.Layers[<span style="color: #a31515;">"inputsGraphicsLayer"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">GraphicsLayer</span>;
graphicsLayer.ClearGraphics();
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> event OnDrawComplete</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"sender"</span><span style="color: grey;">></span><span style="color: green;">object sender</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"args"</span><span style="color: grey;">></span><span style="color: green;">object args</span><span style="color: grey;"></param></span>
<span style="color: blue;">private</span> <span style="color: blue;">void</span> MyDrawObject_OnDrawComplete(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DrawEventArgs</span> args)
{
<span style="color: #2b91af;">Polyline</span> pl = (<span style="color: #2b91af;">Polyline</span>)args.Geometry;
<span style="color: blue;">if</span> (pl.Extent.Width == 0 && pl.Extent.Height == 0)
{
<span style="color: blue;">return</span>;
}
<span style="color: blue;">this</span>.Cursor = <span style="color: #2b91af;">Cursors</span>.Wait;
<span style="color: blue;">this</span>.drawObject.IsEnabled = <span style="color: blue;">false</span>;
<span style="color: blue;">switch</span> (<span style="color: blue;">this</span>.currentOperation)
{
<span style="color: blue;">case</span> <span style="color: #2b91af;">SurfaceSOE</span>.<span style="color: #2b91af;">OperationName</span>.GetLineOfSight:
<span style="color: blue;">this</span>.surfaceSOE.GetLineOfSight(pl, 10, 10);
<span style="color: blue;">break</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> initialize soe</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> <span style="color: blue;">async</span> <span style="color: blue;">void</span> InitializeSOE()
{
<span style="color: blue;">this</span>.Cursor = <span style="color: #2b91af;">Cursors</span>.AppStarting;
<span style="color: blue;">this</span>.surfaceSOE = <span style="color: blue;">new</span> <span style="color: #2b91af;">SurfaceSOE</span>(surfaceSoeUrl, surfaceSoeName, surfaceResourceIndex);
<span style="color: blue;">bool</span> isValid = <span style="color: blue;">await</span> <span style="color: blue;">this</span>.surfaceSOE.Validate();
<span style="color: blue;">if</span> (isValid)
{
<span style="color: blue;">this</span>.surfaceSOE.GetLineOfSightResponseEvent += <span style="color: blue;">new</span> <span style="color: #2b91af;">EventHandler</span>(<span style="color: blue;">this</span>.SurfaceSOE_GetLineOfSightEvent);
}
<span style="color: blue;">else</span>
{
<span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"We are unable to continue due to invalid SOE properties.\nPlease contact your system administrator."</span>, <span style="color: #a31515;">"Can't continue"</span>, <span style="color: #2b91af;">MessageBoxButton</span>.OK, <span style="color: #2b91af;">MessageBoxImage</span>.Stop);
}
<span style="color: blue;">this</span>.Cursor = <span style="color: #2b91af;">Cursors</span>.Arrow;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> event click clear</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"sender"</span><span style="color: grey;">></span><span style="color: green;">object sender</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"e"</span><span style="color: grey;">></span><span style="color: green;">object e</span><span style="color: grey;"></param></span>
<span style="color: blue;">private</span> <span style="color: blue;">void</span> Clear_Click(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">RoutedEventArgs</span> e)
{
<span style="color: #2b91af;">GraphicsLayer</span> graphicsLayer = _map.Layers[<span style="color: #a31515;">"inputsGraphicsLayer"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">GraphicsLayer</span>;
graphicsLayer.ClearGraphics();
<span style="color: blue;">this</span>.Cursor = <span style="color: #2b91af;">Cursors</span>.Arrow;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> event click LOS</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"sender"</span><span style="color: grey;">></span><span style="color: green;">object sender</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"e"</span><span style="color: grey;">></span><span style="color: green;">object e</span><span style="color: grey;"></param></span>
<span style="color: blue;">private</span> <span style="color: blue;">void</span> LOS_Click(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">RoutedEventArgs</span> e)
{
<span style="color: blue;">this</span>.currentOperation = <span style="color: #2b91af;">SurfaceSOE</span>.<span style="color: #2b91af;">OperationName</span>.GetLineOfSight;
<span style="color: blue;">this</span>.currentSymbol = LayoutRoot.Resources[<span style="color: #a31515;">"BlueLineSymbol"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">Symbol</span>;
<span style="color: blue;">this</span>.drawObject.DrawMode = <span style="color: #2b91af;">DrawMode</span>.LineSegment;
<span style="color: blue;">this</span>.drawObject.IsEnabled = <span style="color: blue;">true</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> GetLineOfSight Event</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"sender"</span><span style="color: grey;">></span><span style="color: green;">object sender</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"e"</span><span style="color: grey;">></span><span style="color: green;">object e</span><span style="color: grey;"></param></span>
<span style="color: blue;">private</span> <span style="color: blue;">void</span> SurfaceSOE_GetLineOfSightEvent(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: #2b91af;">GetLineOfSightResponse</span> response = (<span style="color: #2b91af;">GetLineOfSightResponse</span>)e;
<span style="color: blue;">if</span> (response.VisibleLines != <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">Graphic</span> graphic = <span style="color: blue;">new</span> <span style="color: #2b91af;">Graphic</span>()
{
Symbol = LayoutRoot.Resources[<span style="color: #a31515;">"GreenLineSymbol"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">Symbol</span>,
Geometry = response.VisibleLines
};
<span style="color: #2b91af;">GraphicsLayer</span> graphicsLayer = _map.Layers[<span style="color: #a31515;">"inputsGraphicsLayer"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">GraphicsLayer</span>;
graphicsLayer.Graphics.Add(graphic);
}
<span style="color: blue;">if</span> (response.InvisibleLines != <span style="color: blue;">null</span>)
{
<span style="color: #2b91af;">Graphic</span> graphic = <span style="color: blue;">new</span> <span style="color: #2b91af;">Graphic</span>()
{
Symbol = LayoutRoot.Resources[<span style="color: #a31515;">"RedLineSymbol"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">Symbol</span>,
Geometry = response.InvisibleLines
};
<span style="color: #2b91af;">GraphicsLayer</span> graphicsLayer = _map.Layers[<span style="color: #a31515;">"inputsGraphicsLayer"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">GraphicsLayer</span>;
graphicsLayer.Graphics.Add(graphic);
}
<span style="color: blue;">if</span> (!response.IsVisible)
{
<span style="color: #2b91af;">Graphic</span> graphic = <span style="color: blue;">new</span> <span style="color: #2b91af;">Graphic</span>()
{
Symbol = LayoutRoot.Resources[<span style="color: #a31515;">"RedCircleSymbol"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">Symbol</span>,
Geometry = response.PointObstruction
};
<span style="color: #2b91af;">GraphicsLayer</span> graphicsLayer = _map.Layers[<span style="color: #a31515;">"inputsGraphicsLayer"</span>] <span style="color: blue;">as</span> <span style="color: #2b91af;">GraphicsLayer</span>;
graphicsLayer.Graphics.Add(graphic);
}
<span style="color: blue;">this</span>.Cursor = <span style="color: #2b91af;">Cursors</span>.Arrow;
}
}</pre>
<br />
Qui potete scaricare l'esempio in <a href="http://www.studioat.it/studioat/uploads/wpfsurfacesoelos.zip" target="_blank">WPF.</a><br />
<br />
L'analisi di visibilità risulta particolarmente adatta per le valutazioni di impatto ambientale per aree sensibili all'impatto visivo (impianti eolici, viadotti ecc.). E' possibile creare anche mappe di visibilità con la funzione <a href="http://resources.arcgis.com/en/help/main/10.1/00q9/00q900000033000000.htm" target="_blank">Viewshed</a> utile anche ad esempio per sapere qual è una buona posizione per una torre di comunicazione.<br />
<br />
<a href="http://sit.sistemigis.it/Samples/Elevations" target="_blank">Qui</a> in questo esempio sono presenti quasi tutti i metodi dell'interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/002500000877000000.htm" target="_blank">ISurface</a> esposti come<a href="http://sit.sistemigis.it/sit/rest/services/Demo/Surface/MapServer/exts/SurfaceUtility/Help" target="_blank"> SOE rest </a>e quindi utilizzabili con tutti i web client ESRI. L'estensione denominata <a href="http://www.arcgis.com/home/item.html?id=edd67a4f54584eb0bacadf3f997876e1" target="_blank">SurfaceUtility</a> sarà disponibile per il download dopo la <a href="http://www.esri.com/events/devsummit/index.html" target="_blank">Esri International Developer Summit</a> che si terrà dal 25 al 28 marzo 2013 a Palm Springs poichè i metodi dei profili sono ereditati da una SOE che ha sviluppato Esri e che verrà presentata ufficialmente in quell'occasione.<br />
Ora l'estensione SurfaceUtility è disponibile <a href="http://www.arcgis.com/home/item.html?id=1c96538fa81948efb5a2436532964def">qui</a>.<br />
<br />
<a href="http://sit.sistemigis.it/samples/gpxelevations/">Qui</a> potete vedere un sample che utilizza la SOE e il <a href="http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r300000083000000.htm">generate</a> di ArcGIS for Portal per visualizzare un profilo altimetrico da un file <a href="http://it.wikipedia.org/wiki/GPS_eXchange_Format">GPX</a>.<br />
<br />
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938720.068075500000003 -32.052761000000061 71.1121445 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-56054646500103504182013-01-31T11:24:00.000+01:002013-02-13T19:50:21.127+01:00La vita non è bella senza nuvole: i tuoi feature service in cloudLa versione 10.1 di ArcGIS for Server ha migliorato notevolmente il controllo dell'accesso ai dati pubblicati mediante servizi. <br />
<br />
L'amministratore del server ha la possibilità, ora, di registrare cartelle, database e geodatabase, per ArcGIS for Server. La registrazione dei dati aiuta anche il server GIS ad 'aggiustare' i percorsi quando si pubblica tra macchine diverse.<br />
In questo modo un analista GIS ha la possibilità di pubblicare servizi anche tra differenti macchine, senza incorrere in problemi di permessi che potrebbero impedire la pubblicazione. <br />
L'amministratore del server registrerà le cartelle e i database approvati, comunicandoli poi all'analista GIS.<br />
<br />
Tra i possibili scenari, troviamo anche quello di pubblicare feature service su macchine remote alle quali, per vari motivi, non è possibile accedere: firewall, differenti piattaforme, gestione "separata" dei dati su web, pubblicatore e server che lavorano ciascuno su un proprio database, ecc...<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7NblEY7KL-XYQ3m3tbAEQepLxCiN4pPpIhLAvYECk8S4eWcgxMGhOYWZf0oexrLO3_O1SxY_LxOS-FmZC_JRy5TFV5ZbJ8M6W8tU0nryGTpgaR3xQHwbswFpBDsbtnTkRCPuOx2GwNJLx/s1600/fs11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7NblEY7KL-XYQ3m3tbAEQepLxCiN4pPpIhLAvYECk8S4eWcgxMGhOYWZf0oexrLO3_O1SxY_LxOS-FmZC_JRy5TFV5ZbJ8M6W8tU0nryGTpgaR3xQHwbswFpBDsbtnTkRCPuOx2GwNJLx/s1600/fs11.png" /></a></div>
Lo scenario qui sopra, ad esempio, rappresenta la possibilità di mantenere una copia separata dei dati, si intende in un geodatabase enterprise, per utilizzarlo via web.<br />
In questo caso dobbiamo effettuare una copia dei dati dal geodatabase del pubblicatore a quello del server. Si ribadisce che questo scenario può essere realizzato solo se si dispone di un geodatabase di tipo enterprise.<br />
<br />
ArcGIS for Server 10.1 mette però a disposizione una opzione, <em>Create geodata service</em>, per trasferire i dati sul geodabase enterprise del server. <br />
In pratica, quando si registrano i due geodatabase, questa opzione crea automaticamente un servizio geodata che possiamo utilizzare per inviare manualmente una replica dei dati (si intende tra il geodatabase del pubblicatore e quello del server).<br />
<br />
Possiamo anche utilizzare il servizio geodata per sincronizzare i geodatabase, assicurandoci così che qualsiasi modifica effettuata sul geodatabase del pubblicatore, sia propagato al geodatabase del server.<br />
Un'opzione molto vantaggioso per distribuzioni in ambienti cloud, dove non è richiesto che qualcuno debba accedere alla macchina per trasferire i dati.<br />
<br />
Si tratta di uno scenario indicato anche per pubblicare feature service on-premises e su cloud.<br />
Ad esempio, in questa ipotesi, le modifiche degli editor on-premises possono essere inviate al geodatabase del server, rendendole disponibili agli utenti finali del feature service.<br />
Viceversa, se un web editor effettua modifiche alle feature sul geodatabase del server, le modifiche possono essere sincronizzate con il geodatabase del pubblicatore.<br />
<br />
Questo scenario prevede di impostare la replica in modalità <em>two-way,</em> perchè la sincronizzazione dovrà avvenire in entrambe le direzioni (parent-child e child-parent), oltre ad essere ripetuta più volte.<br />
<br />
Vediamo ora quali sono i passi da seguire per impostare questo scenario.<br />
Supponiamo di avere, sulla macchina del pubblicatore, un geodatabase enterprise (nome connessione: testegdb.sde) che ospita due feature class (TestPoint e TestPolygon).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnvqhLq5Mm27HE0YMbWudZCACI0LSr4miu76HUckN8jGp6-xXg4r1Urex7zCtGoF2bDxCzfhKAdsjPRFJ7YT69QTYojoAYukhUXK9hYpkHXn_69UsOi0RlNlAct0uP_3FfiHiSZ4y-jPNx/s1600/fs1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnvqhLq5Mm27HE0YMbWudZCACI0LSr4miu76HUckN8jGp6-xXg4r1Urex7zCtGoF2bDxCzfhKAdsjPRFJ7YT69QTYojoAYukhUXK9hYpkHXn_69UsOi0RlNlAct0uP_3FfiHiSZ4y-jPNx/s1600/fs1.png" /></a></div>
<br />
<br />
Per prima cosa, prepariamo le feature class per la replica.<br />
I dati devono essere registrati come versionati senza l'opzione <em>move edits to base </em>e ogni dataset deve avere una colonna GlobalID (colonna che mantiene l'univocità della riga tra i geodatabase).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlAQ7sZujH5ndTdf4KyxzkrsSuBEBoeihVMIGOQqHaNdJhjd7VfKcJ63YG_tja_71XCMCbN7BaGMc-bUxis48c88FoZg2ZP7Ux20XgDfaXK-VYdGmQdNWz3s01IvFIjO_LUrtBjCNpds5/s1600/fs2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlAQ7sZujH5ndTdf4KyxzkrsSuBEBoeihVMIGOQqHaNdJhjd7VfKcJ63YG_tja_71XCMCbN7BaGMc-bUxis48c88FoZg2ZP7Ux20XgDfaXK-VYdGmQdNWz3s01IvFIjO_LUrtBjCNpds5/s1600/fs2.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgayfpV9bETWOtmvx2bX9hOOovbe6FJZfrb5M6pOKGueitQT9NHPvF1oqv0X14VIxDsLXN5w8SwQg1WcMUhrYW5kybnTDWOeZQvrROx48lDvamzZTyXpxv7_PubwoL73ZRKpCrRnl8LCHyS/s1600/fs3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgayfpV9bETWOtmvx2bX9hOOovbe6FJZfrb5M6pOKGueitQT9NHPvF1oqv0X14VIxDsLXN5w8SwQg1WcMUhrYW5kybnTDWOeZQvrROx48lDvamzZTyXpxv7_PubwoL73ZRKpCrRnl8LCHyS/s1600/fs3.png" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEji4gfq9qAizuH3U3tHuxkEzQe3JfXZwRJF0ZEBnVvD-Jz1jenWAVdAg-8ekiPjKYdNKjdDq_m1FoU2GxLDDI4qeyRPOSC36tuYhfy88EvaOfPztz5L1BbIJnWyMMj0ri2dYMze6rTA-EZv/s1600/fs4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEji4gfq9qAizuH3U3tHuxkEzQe3JfXZwRJF0ZEBnVvD-Jz1jenWAVdAg-8ekiPjKYdNKjdDq_m1FoU2GxLDDI4qeyRPOSC36tuYhfy88EvaOfPztz5L1BbIJnWyMMj0ri2dYMze6rTA-EZv/s1600/fs4.png" /></a></div>
<br />
<br />
<br />
<br />
Caricando le feature class in ArcMap, possiamo notare come le nostre righe siano rese univoche dal GlobalID, per le operazioni di sincronizzazione da parte della replica.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ2ohiPnIyQUfRynyF6mpvMKTBihptX8yCe5QoeBig02TMrkRpf1spWUW9hIo8ogq-6afwd267njVax1DbYCIOdBO2dpYNQhiThq83sSwFXItQ6x_CR7wBPw97V5oDqzrMikMDrWFlLpFR/s1600/fs5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ2ohiPnIyQUfRynyF6mpvMKTBihptX8yCe5QoeBig02TMrkRpf1spWUW9hIo8ogq-6afwd267njVax1DbYCIOdBO2dpYNQhiThq83sSwFXItQ6x_CR7wBPw97V5oDqzrMikMDrWFlLpFR/s1600/fs5.png" /></a></div>
<br />
Una volta predisposto il documento di mappa con ArcMap, pubblichiamo il servizio.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ38NJSlAU9jSOfc9BSZcM9pU6MS7wvWAWAFFq6Mcel1MdGTnIFvrQ5xrc-Yts3DX57flNVum7Qgc4Y6gnD73kfWi05OK2PIxobRkORX_6yYyOmy3CfrKIreZNP9GA5SxivJ3l6p1y32Sn/s1600/fs6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ38NJSlAU9jSOfc9BSZcM9pU6MS7wvWAWAFFq6Mcel1MdGTnIFvrQ5xrc-Yts3DX57flNVum7Qgc4Y6gnD73kfWi05OK2PIxobRkORX_6yYyOmy3CfrKIreZNP9GA5SxivJ3l6p1y32Sn/s1600/fs6.png" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXxe6FEoBOOZ82ECbAnF39XygmBhwOhuo1yBYj0wMnAvoRTYcROc6JpwN42JgEiiEZFjCtfeduF1AO0UOoABNFhoszEOzj6saA_3R3YvBcXEFp0m8vtzu6xhyphenhyphen53zlNyskSRBHzrJ9j3zu4/s1600/fs7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXxe6FEoBOOZ82ECbAnF39XygmBhwOhuo1yBYj0wMnAvoRTYcROc6JpwN42JgEiiEZFjCtfeduF1AO0UOoABNFhoszEOzj6saA_3R3YvBcXEFp0m8vtzu6xhyphenhyphen53zlNyskSRBHzrJ9j3zu4/s1600/fs7.png" /></a></div>
<br />
Selezioniamo la connessione remota e assegnamo un nome al servizio.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhryf3JdyV9o8TMSPI1WpGbQt5aSJrRyP2jfXz1vAo9Gca4Cj6jeaLY4job38h0iQIi6iYfp018e_xk13aD1w9EM8v0UB0X_f0_FN-nOYPd2-zNB8AyPxl_1b_O8fhmeDDriEcucK78UVSw/s1600/fs8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhryf3JdyV9o8TMSPI1WpGbQt5aSJrRyP2jfXz1vAo9Gca4Cj6jeaLY4job38h0iQIi6iYfp018e_xk13aD1w9EM8v0UB0X_f0_FN-nOYPd2-zNB8AyPxl_1b_O8fhmeDDriEcucK78UVSw/s1600/fs8.png" /></a></div>
<br />
Tra le <em>Capabilities,</em> selezioniamo <em>Feature Access, </em>opzione necessaria per esporre il servizio come feature service.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEX5vtvX0w0OH9BImj1kEoTXLi14ranHNceWH_ZBmAVt33Hae0yuMGcirLI8TuRY4gjjUo2mpqU6WL5vPVsnIBW3t-aATv8PylhDrASP_yu3kcSQyhHoo6JOVeX_w5U4zWJrHCaeBLUpoL/s1600/fs10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEX5vtvX0w0OH9BImj1kEoTXLi14ranHNceWH_ZBmAVt33Hae0yuMGcirLI8TuRY4gjjUo2mpqU6WL5vPVsnIBW3t-aATv8PylhDrASP_yu3kcSQyhHoo6JOVeX_w5U4zWJrHCaeBLUpoL/s1600/fs10.png" /></a></div>
<br />
Analizzando il documento di mappa prima della pubblicazione, ArcGIS segnala che il feature service richiede un database registrato.<br />
In effetti, abbiamo indicato una connessione remota ad un ArcGIS for Server, ma il sistema necessita anche delle informazioni per sapere "come e dove" replicare i dati nel server remoto.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ1xVgXCBqdEsi-utdGSXwaGbKwN8JgbbzdIevmTcntXjl43nlEiLgWrL3-P09vgadpKduacKvYON6rwrT8mP8ads8PqZd2EosGQvSt70VpI8vx3E1OFkrIgeHXu4MuMzKpVPXd5FoW0VF/s1600/fs12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ1xVgXCBqdEsi-utdGSXwaGbKwN8JgbbzdIevmTcntXjl43nlEiLgWrL3-P09vgadpKduacKvYON6rwrT8mP8ads8PqZd2EosGQvSt70VpI8vx3E1OFkrIgeHXu4MuMzKpVPXd5FoW0VF/s1600/fs12.png" /></a></div>
<br />
<br />
Per risolvere il problema, apriamo il <em>Data Stores</em> con un doppio click sulla segnalazione dell'<em>Analyze</em> e aggiungiamo i database da registrare.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV5e1aJRQa9HmpFk3-bK7SXSyZ9vf0WWZCA1HDb8XKus9vlcQQpb_qrsNGFfjnKylWkmzDjnZt1bvY8-57VcSiLMjL3_2p4OZBAB6fQ7c6EGItWj3NgELQqdV-FOqI9uNiNMIYCthSgh33/s1600/fs13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV5e1aJRQa9HmpFk3-bK7SXSyZ9vf0WWZCA1HDb8XKus9vlcQQpb_qrsNGFfjnKylWkmzDjnZt1bvY8-57VcSiLMjL3_2p4OZBAB6fQ7c6EGItWj3NgELQqdV-FOqI9uNiNMIYCthSgh33/s1600/fs13.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Diamo un nome alla registrazione (in questo esempio egdb) ed importiamo la connessione del geodatabase del pubblicatore.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRDB0MAMsxnCCKhnbhL5YfZ5ausKH5GYRom8dqsTK2NkYI9HnJh8y1dhDOKNWnVVXXlGBzHNIWM8j7XZbJWQcJfkxz7hr6s8q_zltISOANuOQ8_cscFpwNDasWvOE7Ewp3EMTkhIrghZKI/s1600/fs14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRDB0MAMsxnCCKhnbhL5YfZ5ausKH5GYRom8dqsTK2NkYI9HnJh8y1dhDOKNWnVVXXlGBzHNIWM8j7XZbJWQcJfkxz7hr6s8q_zltISOANuOQ8_cscFpwNDasWvOE7Ewp3EMTkhIrghZKI/s1600/fs14.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIClXhhJmiZwZKkcouiVygzFeiCABVicJv47ibHJmCG5FbHOI_-fgWeGPvCDEaPuBzPoD62wvYYH9COORYA5OdMnkjSSN0XXV1r90sbPqb6tf94RHNj_w9g5Q-otB-KPSVxEksL7RGFq-y/s1600/fs15.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIClXhhJmiZwZKkcouiVygzFeiCABVicJv47ibHJmCG5FbHOI_-fgWeGPvCDEaPuBzPoD62wvYYH9COORYA5OdMnkjSSN0XXV1r90sbPqb6tf94RHNj_w9g5Q-otB-KPSVxEksL7RGFq-y/s1600/fs15.png" /></a></div>
<br />
Per quel che riguarda il geodatabase del server remoto, deselezioniamo <em>Same as publisher database connection, </em>perchè non utilizziamo lo stesso geodatabase del pubblicatore.<br />
Selezioniamo, invece, <em>Create geodata service,</em> perchè utilizziamo il servizio di geodata per la replica dei dati sul geodatabase del server ed importiamo la connessione al geodatabase del server. Connessione che serve al servizio geodata per accedere ai dati sul server remoto, visto che non possiamo accedervi direttamente con la connessione impostata sul <em>server database connection</em>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLXXWQJkXvOa1v2EytCpSqXU2mubPQWYUsOFZ0gLw5DGvk-kwmUlsQv6t8uyndJHzbTvEzjzjrJgYqD66UWZGFaLzDeW2D74WJG9NBuU0i3RfJ2Vkcp28F5uyWIOGDmeQRa-999OTLTP8f/s1600/fs16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLXXWQJkXvOa1v2EytCpSqXU2mubPQWYUsOFZ0gLw5DGvk-kwmUlsQv6t8uyndJHzbTvEzjzjrJgYqD66UWZGFaLzDeW2D74WJG9NBuU0i3RfJ2Vkcp28F5uyWIOGDmeQRa-999OTLTP8f/s1600/fs16.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC2udZRzDcfFXH2v8IkMFeTaktWTHESUS6kn4prqB_7pPNmeVYSyrX3zDn6cVu348t3Sf53TnekzDfCbwJIlIFI-KsEu76hY4ZgWuwmrwZJ3FjWkqPoK5LRg94brKNNL5Mo9ANwQy9KSbu/s1600/fs17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC2udZRzDcfFXH2v8IkMFeTaktWTHESUS6kn4prqB_7pPNmeVYSyrX3zDn6cVu348t3Sf53TnekzDfCbwJIlIFI-KsEu76hY4ZgWuwmrwZJ3FjWkqPoK5LRg94brKNNL5Mo9ANwQy9KSbu/s1600/fs17.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuBqbQYFXPaKZLJf-9dIqovEAJZ3JUqIy5XSLAAkm_eCLqIJmlxtmj8LHrSlBAFrqK30_gnMpfCg5Lv2nCfbkexh5tbWQ0-YifXwud5H3mJnZfi_RV8BF7fED8EK_l0hILXa3Hr1g-8mV5/s1600/fs18.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuBqbQYFXPaKZLJf-9dIqovEAJZ3JUqIy5XSLAAkm_eCLqIJmlxtmj8LHrSlBAFrqK30_gnMpfCg5Lv2nCfbkexh5tbWQ0-YifXwud5H3mJnZfi_RV8BF7fED8EK_l0hILXa3Hr1g-8mV5/s1600/fs18.png" /></a></div>
<br />
Confermate le impostazioni, viene creato il geodata service sul server remoto (il nome è lo stesso della registrazione).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg-8gewp4UJUWJCZeN4Bv0bToCBe1XYmck3PCNQhUym-36-2jt2-wqhk_Hx8Q9pld431mIu5yA8VPNaOkzr1RgcTv2Qnn4vA4KmrWmJlepNOdJiMrW3elHkECXo5fNqJKZrTvo8FDCJQTG/s1600/fs19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg-8gewp4UJUWJCZeN4Bv0bToCBe1XYmck3PCNQhUym-36-2jt2-wqhk_Hx8Q9pld431mIu5yA8VPNaOkzr1RgcTv2Qnn4vA4KmrWmJlepNOdJiMrW3elHkECXo5fNqJKZrTvo8FDCJQTG/s1600/fs19.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqWzIqH9bSJBFTIAY9M6fZz25z0asbS1kRWSGFH0XjYa88Jufld23I_YY5qfxaXg7VFX03wrQoyk2BopI1Sw6PxTK8HqxELSgujyChrYuhIL6qAWn38X49_2ImFYetoQOmyIuG21I222JA/s1600/fs21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqWzIqH9bSJBFTIAY9M6fZz25z0asbS1kRWSGFH0XjYa88Jufld23I_YY5qfxaXg7VFX03wrQoyk2BopI1Sw6PxTK8HqxELSgujyChrYuhIL6qAWn38X49_2ImFYetoQOmyIuG21I222JA/s1600/fs21.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
Se analizziamo nuovamente il documento, possiamo verificare che gli errori e gli avvisi relativi alla registrazione dei database sono stati risolti.<br />
Il sistema, ora, ha tutti gli elementi per pubblicare i dati sul server remoto, anche per i servizi futuri che accederanno ai dati presenti nel documento di mappa.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENK5SMf5fA73mcHO9xsENZmJZ5L6ajM-aNC5V86D24Dny-Hv7mfMxtp-ZvtTPi2blXjCWsxYgdF2SQKa2tCNVQ9EjbEq0GYVvt5jaJrJ40nCrdxvB-J509ryexqMTL3GZa81XBPkqWO3L/s1600/fs20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENK5SMf5fA73mcHO9xsENZmJZ5L6ajM-aNC5V86D24Dny-Hv7mfMxtp-ZvtTPi2blXjCWsxYgdF2SQKa2tCNVQ9EjbEq0GYVvt5jaJrJ40nCrdxvB-J509ryexqMTL3GZa81XBPkqWO3L/s1600/fs20.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
Prima di pubblicare il servizio, creiamo una replica di tipo <em>Two way</em>. <br />
Selezioniamo in ArcMap la toolbar <em>Distributed Geodatabase </em>e clicchiamo su <em><strong>Create Replica </strong></em><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl7ekBdHRDcAC5xJTxgS6ZnvEumMBw45Cne7f0TCvdtrxO1y2EP33xVMW7x7U-q6UF9r0tX6MYCpqm480RZt4FhLJFP9j9hCmodHJhfbpfmY_9MgUnYTQb3ssEODE1UvANm4zr0yo9abA1/s1600/fs22.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl7ekBdHRDcAC5xJTxgS6ZnvEumMBw45Cne7f0TCvdtrxO1y2EP33xVMW7x7U-q6UF9r0tX6MYCpqm480RZt4FhLJFP9j9hCmodHJhfbpfmY_9MgUnYTQb3ssEODE1UvANm4zr0yo9abA1/s1600/fs22.png" /></a></div>
<br />
<br />
In questo caso replichiamo i dati scegliendo, come geodatabase, il servizio geodata precedentemente creato dalla registrazione dei geodatabase, per ultimo diamo un nome alla replica (in questo esempio MyReplica).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtlGpiFrEtDAhMH2AYT1JamRpR18jZSdlVcr1WWoXrAmqwpRm2jKfJv9NJkyQC0dD0B44i3xSUn7-l8MWXUpnwJkCLW9nbiF193ttz87shTjn7ldjy6qJe8mpWqcRaDyYAcPZ1otwd6Or/s1600/fs23.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtlGpiFrEtDAhMH2AYT1JamRpR18jZSdlVcr1WWoXrAmqwpRm2jKfJv9NJkyQC0dD0B44i3xSUn7-l8MWXUpnwJkCLW9nbiF193ttz87shTjn7ldjy6qJe8mpWqcRaDyYAcPZ1otwd6Or/s1600/fs23.png" /></a></div>
<br />
Una volta confermato il passaggio di cui sopra, viene creata la replica tra il geodatabase del pubblicatore e quello sul server remoto.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif6mW4ut0XdKJL1J2awm64QBXRx0mXMnThs-1ztvwMd7jaeuOL9ZiYtqDLTPx_sOGRfpTgvnQu6JzDjivjjs__4AKY0BFzm_ghKXQiEQsgbo-gzn7xPLQwGoK3YgjDGFSXDm_VejAgmGfF/s1600/fs24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif6mW4ut0XdKJL1J2awm64QBXRx0mXMnThs-1ztvwMd7jaeuOL9ZiYtqDLTPx_sOGRfpTgvnQu6JzDjivjjs__4AKY0BFzm_ghKXQiEQsgbo-gzn7xPLQwGoK3YgjDGFSXDm_VejAgmGfF/s1600/fs24.png" /></a></div>
<br />
<br />
Siamo ora pronti per pubblicare il nostro feature service e quindi clicchiamo su <em>Publish. </em><br />
Tutte le precedenti operazioni passano dalla connessione selezionata (in questo esempio myCloud) quando abbiamo selezionato dal menu la voce <em>File</em> -> <em>Share As</em> -> <em>Service... </em>Pertanto sul server remoto non occorre aprire nessuna porta particolare, visto che passa tutto su http e/o https.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjte4aCthLST0Wyo7Qv8NIi6ojK_sXGgAiW7EzIKWJmxCWFH5SSwz0Ok_Re4wvs8vza9qLzFho6UcT9QpuXTGYupICDoCkEGO_KOGtCPjltPocSANx3eLfwHZ1weIZs8MY-6vgdWukHJIyV/s1600/fs25.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjte4aCthLST0Wyo7Qv8NIi6ojK_sXGgAiW7EzIKWJmxCWFH5SSwz0Ok_Re4wvs8vza9qLzFho6UcT9QpuXTGYupICDoCkEGO_KOGtCPjltPocSANx3eLfwHZ1weIZs8MY-6vgdWukHJIyV/s1600/fs25.png" /></a></div>
<br />
<br />
Siamo ora in grado di accedere e visualizzare il feature service.<br />
Possiamo anche servirci di <a href="http://www.arcgis.com/home/webmap/viewer.html?useExisting=1" target="_blank">arcgis.com</a> per utilizzare il servizio preventivamente protetto da user e password: impostare in ArcGIS for Server la protezione del servizio mediante ruoli-utenti.<br />
Quando <a href="http://www.arcgis.com/home/webmap/viewer.html?useExisting=1" target="_blank">arcgis.com</a> 'vede' che il servizio è protetto, apre una finestra di dialogo per inserire le credenziali di accesso.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1Ww2rbqenPMB8xXjOVRtRlZrEpzPSkYVt-57ScYSAu6qvDWmI-kEglx_gaskNkeZgK0ptHFuHZhSGWqC0Yo6gu3GxpxrI-Ey8vlrorv0PRbA9Ev3L68jS6iyixnbsFq-N6E-9yjfD85P7/s1600/fs27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1Ww2rbqenPMB8xXjOVRtRlZrEpzPSkYVt-57ScYSAu6qvDWmI-kEglx_gaskNkeZgK0ptHFuHZhSGWqC0Yo6gu3GxpxrI-Ey8vlrorv0PRbA9Ev3L68jS6iyixnbsFq-N6E-9yjfD85P7/s1600/fs27.png" /></a></div>
<br />
Con il pulsante <em>Modifica, </em>inseriamo qualche dato. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhosdU5tNneAXKzl6eZZMQQ5aRVzjusEivOA6ZeZdTmUp3ZFXeN1L7cp8dkyTrcjyq7WMNkhiW1TZOoatBp8RWd30nBb9sMIPbLcd57__aPO3zJHbEg1Z06bj3CmNhIgZRKAF5JW-Si5Fkr/s1600/fs28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhosdU5tNneAXKzl6eZZMQQ5aRVzjusEivOA6ZeZdTmUp3ZFXeN1L7cp8dkyTrcjyq7WMNkhiW1TZOoatBp8RWd30nBb9sMIPbLcd57__aPO3zJHbEg1Z06bj3CmNhIgZRKAF5JW-Si5Fkr/s1600/fs28.png" /></a></div>
<br />
In questo esempio inserisco il punto con Id=7 nella feature class puntuale.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiyLtBUS3kLQE20f4pb8NI8RhVf5Lf7juXGpl1Y2EyQsaUPAqWs2aSJehO4Iovrq4xtfoaqLl9tbKKKigowG2ssaW9zeeEKqGnr3kN9C5xIrKqix1rb6dGTsFVNXC6WgxTdtXlCfM-x3Nb/s1600/fs30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiyLtBUS3kLQE20f4pb8NI8RhVf5Lf7juXGpl1Y2EyQsaUPAqWs2aSJehO4Iovrq4xtfoaqLl9tbKKKigowG2ssaW9zeeEKqGnr3kN9C5xIrKqix1rb6dGTsFVNXC6WgxTdtXlCfM-x3Nb/s1600/fs30.png" /></a></div>
<br />
<br />
...ed ora sincronizziamo le modifiche effettuate su web nel nostro geodatabase.<br />
<br />
Da ArcMap possiamo, selezionando <em>Synchronize Changes</em>, sincronizzare dal child al parent.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC6eqv_OMiE1xD115or_sYnFrTtwCY0tqZUxWZUxB0FrhgVONay37O011xPLQusOP21kTbVsnUy8YCOmLbdy_ju5EsgVQOf_z4TESh_weW0LHwI7duxnrtRvGgAnq215mMnVcIYtaTXtUV/s1600/fs32.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC6eqv_OMiE1xD115or_sYnFrTtwCY0tqZUxWZUxB0FrhgVONay37O011xPLQusOP21kTbVsnUy8YCOmLbdy_ju5EsgVQOf_z4TESh_weW0LHwI7duxnrtRvGgAnq215mMnVcIYtaTXtUV/s1600/fs32.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmD1q8BrashTNbNWSrEZvnFPjbqP9nLkIdNpEluTPUS9PL_n3RTUl16oPbsCZ2AAL0KQUM3nmAhOc4iA0seTd_ywpUbTgSmgdFXzsCulSm2Es039Vew8R4UD2DVtv9pEz4TmkUvfro0vMT/s1600/fs33.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmD1q8BrashTNbNWSrEZvnFPjbqP9nLkIdNpEluTPUS9PL_n3RTUl16oPbsCZ2AAL0KQUM3nmAhOc4iA0seTd_ywpUbTgSmgdFXzsCulSm2Es039Vew8R4UD2DVtv9pEz4TmkUvfro0vMT/s1600/fs33.png" /></a></div>
<br />
Una volta sincronizzato, possiamo vedere le modifiche effettuate: nel nostro caso è stato aggiunto un punto su web (punto con Id=7), che è stato propagato nel geodatabase del pubblicatore.<br />
Durante la sincronizzazione, i cambi sono effettuati con operazioni di <em>reconcile</em> e <em>post</em> nella versione replica. <br />
Durante l'operazione di <em>reconcile</em> possono manifestarsi dei conflitti. In questo caso possiamo scegliere quale policy utilizzare per gestirli; possiamo anche scegliere la configurazione per far scattare il conflitto a livello di colonna o adi riga.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQeb-GZlA4EHkpe8EDPdAFj6z72TyPYYfdpKW7BV8eIfxn0Ax_37iOtJzLTgZwQ_3PBMSCVfwr3tv_8eztYj1eH038JS1eXEASOLMQe2sdU_VxDv2WsW9t33FNnX8JMMKvPngSHbbq-Wvd/s1600/fs34.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQeb-GZlA4EHkpe8EDPdAFj6z72TyPYYfdpKW7BV8eIfxn0Ax_37iOtJzLTgZwQ_3PBMSCVfwr3tv_8eztYj1eH038JS1eXEASOLMQe2sdU_VxDv2WsW9t33FNnX8JMMKvPngSHbbq-Wvd/s1600/fs34.png" /></a></div>
<br />
Poichè abbiamo impostato una replica <em>two way</em>, possiamo modificare i dati direttamente sul geodatabase del pubblicatore e propagare le modifiche su web.<br />
Ad esempio aggiungiamo il poligono con Id =4...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinubLhGmPG7om2YXHESBF60NpegMZ45P4cfrlPS9xrd28p8QTENiug3r5eI_eKI2BrMrkxAoJPooE9Rh5cimcFcbDjBUXYK2zqbOnRGaVBvl9n-yEKOnTGBYwGVec3Fz-ElV08WYlIBeLa/s1600/fs35.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinubLhGmPG7om2YXHESBF60NpegMZ45P4cfrlPS9xrd28p8QTENiug3r5eI_eKI2BrMrkxAoJPooE9Rh5cimcFcbDjBUXYK2zqbOnRGaVBvl9n-yEKOnTGBYwGVec3Fz-ElV08WYlIBeLa/s1600/fs35.png" /></a></div>
<br />
Sincronizziamo come sopra ma, questa volta, dal <em>parent</em> al <em>child</em>.<br />
Possiamo anche utilizzare l'opzione <em>Both </em>per sincronizzare contemporaneamente in entrambe le direzioni (parent to child e child to parent).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTP22kZh5mut6uGUB0J5PXnp3Jj3-nNMVVvh0xh-Blr8TCW2eIg7f4JY8PnXl5NcWngGsap8_FASUn0p3MdDQBXDt3UYk46eLJ76TvJblq1iaiSOXhgzdUYmhtWseltKBPiUytn64VbhuS/s1600/fs36.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTP22kZh5mut6uGUB0J5PXnp3Jj3-nNMVVvh0xh-Blr8TCW2eIg7f4JY8PnXl5NcWngGsap8_FASUn0p3MdDQBXDt3UYk46eLJ76TvJblq1iaiSOXhgzdUYmhtWseltKBPiUytn64VbhuS/s1600/fs36.png" /></a></div>
<br />
...e constatare la modifica (aggiunta del poligono con i relativi attributi) direttamente su web.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPfO4M0mG5zZdDoTrPsw6hAPxHBr9Y7Q2GrROOxQgGHm6rIa2kZadYOe04pEJFuUcbna4oqIrfJQh5ckSTsbSlQASk2qf5iP4I7o0OnfyNr4Cc_OrdUue17xd02aU52G11CnCG0eAbFlwf/s1600/fs38.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPfO4M0mG5zZdDoTrPsw6hAPxHBr9Y7Q2GrROOxQgGHm6rIa2kZadYOe04pEJFuUcbna4oqIrfJQh5ckSTsbSlQASk2qf5iP4I7o0OnfyNr4Cc_OrdUue17xd02aU52G11CnCG0eAbFlwf/s1600/fs38.png" /></a></div>
<br />Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.255832999999938722.8855095 -32.052761000000061 68.294710500000008 50.564426999999938tag:blogger.com,1999:blog-8323071861123024882.post-84773091808899147722012-12-24T20:29:00.001+01:002012-12-24T20:29:25.673+01:00La segmentazione dinamica logora chi non ce l’ha!La segmentazione dinamica è il processo per calcolare la shape delle posizioni route al volo lungo feature lineari calibrate basandosi su tabelle eventi per le quali la misura (m) delle distanze è disponibile. Una feature lineare calibrata o route è una feature di tipo polyline che ha i valori di m (misura) ed un identificatore. Pertanto una route è
semplicemente una qualsiasi feature lineare sulla quale possono essere localizzati eventi.<br />
<br />
Si possono organizzare le posizioni route in tabelle basate su un tema comune, le tabelle eventi. Per esempio, cinque tabelle eventi contenenti informazioni su limiti di velocità, anno di riasfaltamento, stato della pavimentazione, segnali stradali e frequenza incidenti possono riferire ad una route feature class rappresentante il reticolo stradale.<br />
<br />
Una tabella eventi è una qualsiasi tabella che contenga un campo di identificazione della route ed almeno un campo per la misura (m). Le tabelle contenenti posizioni route puntuali hanno un campo di misura, mentre le tabelle contenenti posizioni route lineari ne hanno due. Il campo che identifica la route si 'aggancia' all’identificatore di route nella route feature class (non è necessario che questi abbiano lo stesso nome).
<br />
<br />
Una route event source fornisce una tabella eventi come una feature class dinamica. Ogni riga della tabella è rappresentata come una feature la cui shape è calcolata al volo ogni volta che è richiesto: questa è la segmentazione dinamica. <br />
<br />
Nella seguente illustrazione mostriamo il concetto di segmentazione dinamica:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs57Kl9sqtmNXViZ-68f-03I-S_lwgQMVikd_D9cPO8rczCFARhcySwtudTeaN9U8mdu3OXV6jc6s52GVX3gzPtplr71lSyjLQpCF7dYSxZseNxkWnTzM-OlXyzyoDkVND8rlptsvPV_W2/s1600/dn1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="388" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs57Kl9sqtmNXViZ-68f-03I-S_lwgQMVikd_D9cPO8rczCFARhcySwtudTeaN9U8mdu3OXV6jc6s52GVX3gzPtplr71lSyjLQpCF7dYSxZseNxkWnTzM-OlXyzyoDkVND8rlptsvPV_W2/s640/dn1.png" width="640" /></a></div>
<br />
<br />
In una route event source, c’è una feature per ogni riga della tabella eventi originale. A volte, comunque, le feature hanno shape vuote. Ciò accade perché si è verificata una qualche ragione per la quale l’evento non è stato localizzato propriamente. In alcuni ad esempio, si può localizzare un evento solo parzialmente (solo con eventi lineari). La seguente illustrazione mostra alcuni tipi di errore:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ492hKx2ppXTwBFZLMdBpx10i_6mYc3TR5WkKbstW2uBx5iNsBVtgv_uOrmHAkyaAY9rqyUuBlSAVhyphenhyphenSGdxvIqFRwlzNm0QTwvlP2HFhZ873OON5IAxKuvgTTX69N10qKLCr8DroMSeQP/s1600/dn2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ492hKx2ppXTwBFZLMdBpx10i_6mYc3TR5WkKbstW2uBx5iNsBVtgv_uOrmHAkyaAY9rqyUuBlSAVhyphenhyphenSGdxvIqFRwlzNm0QTwvlP2HFhZ873OON5IAxKuvgTTX69N10qKLCr8DroMSeQP/s640/dn2.png" width="640" /></a></div>
<br />
<br />
La seguente illustrazione mostra il modello a oggetti per la segmentazione dinamica:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_SWSPoneIzPw5jv93QH4SrS4xXDxh7yJyS1TrDxVpYNzGBLLbuxfML1bkFwnUgESR-T3meYI1fRDd9lJtE_JlB_AYrRkcCmWnApmaVRn8VcD6CmOBNPcw_UblAYGnhfCLbUZBHKUx5iYK/s1600/dn3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_SWSPoneIzPw5jv93QH4SrS4xXDxh7yJyS1TrDxVpYNzGBLLbuxfML1bkFwnUgESR-T3meYI1fRDd9lJtE_JlB_AYrRkcCmWnApmaVRn8VcD6CmOBNPcw_UblAYGnhfCLbUZBHKUx5iYK/s640/dn3.png" width="528" /></a></div>
<br />
<br />
Per quel che riguarda lo sviluppo, abbiamo a disposizione il Locator, una classe astratta che specifica tutti i tipi di oggetti locator. Tra i tipi di locator ci sono: quelli per indirizzi, route (quello che siamo illustrando), coordinate x y e nomi di località. Il locator combina dati di riferimento con un metodo di posizionamento.
<br />
<br />
L’interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000004p3000000.htm" target="_blank">ILocator</a> fornisce accesso alle proprietà di un locator.
<br />
<br />
Il RouteLocator è una classe astratta che trasforma una posizione route in una shape visualizzabile su mappa. Le classi astratte Locator e RouteLocator sono mostrate nella seguente illustrazione:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU43QdTpeaEyLQb1P89TUAaZ-aRkx6SA7qecUOdO4uBUxhQ8yQbqOIjAWV-L4JXMbViGIyQRpA0u3KJgvh164RBLlWJ_rffLBMjHTyeWN_ZNa8fGZKJ3hN5inZpgtHXG8zWdNa8-KcVJq1/s1600/dn4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjU43QdTpeaEyLQb1P89TUAaZ-aRkx6SA7qecUOdO4uBUxhQ8yQbqOIjAWV-L4JXMbViGIyQRpA0u3KJgvh164RBLlWJ_rffLBMjHTyeWN_ZNa8fGZKJ3hN5inZpgtHXG8zWdNa8-KcVJq1/s1600/dn4.png" /></a></div>
<br />
<br />
La posizione route descrive una posizione lungo una route o una porzione di route tra un DA e un A di misure (m). L’interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/0031000000ts000000.htm" target="_blank">IRouteLocator2</a> eredita da <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/0031000000tr000000.htm" target="_blank">IRouteLocator</a> ed è utile per restituire le proprietà di un oggetto RouteLocator e per determinare la shape delle posizioni route ed eventi.
Il metodo <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/0031000000tv000000.htm" target="_blank">Identify</a> è utile per identificare le posizioni di route utilizzando un envelope. Quando utilizziamo ArcMap, un metodo consigliato è utilizzare la tolleranza del map document:
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"> <span style="color: #2b91af;">IEnvelope</span> envelope = mxDoc.CurrentLocation.Envelope;
envelope.Expand(mxDoc.SearchTolerance, mxDoc.SearchTolerance, <span style="color: blue;">false</span>); </pre>
<br />
Per route locator, la proprietà <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/0031000000vv000000.htm" target="_blank">RouteFeatureClass</a> può essere uno shapefile PolylineM o una feature class Polyline (con valori m) in un personal, file o ArcSDE geodatabase. <br />
Questo significa che le route sono memorizzate in una feature class dove:
<br />
<br />
<div align="center">
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: #2b91af;">IGeometryDef</span>.GeometryType = esriGeometryPolyLine e <span style="color: #2b91af;">IGeometryDef</span>.HasM = <span style="color: blue;">true</span>
</pre>
</div>
<br />
<a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000012w000000.htm" target="_blank">RouteMeasureLocator</a> è un tipo di RouteLocator. Esso determina la shape di una posizione route associando i valori di misura delle posizioni route a quelli memorizzati nella feature route.<br />
Il RouteMeasureLocator è creato tramite la controparte del suo oggetto nome, <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000012z000000.htm" target="_blank">RouteMeasureLocatorName</a>. L’oggetto RouteMeasureLocator è mostrato nella seguente figura:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6_tCo2Rj70dFM3kTWbDQjpz8oVYrzMs-yz1SiPOH_PnHvCZ11AYV6Qngsur9HuiuNVomNKe_nH2BWjMoH6AYuao6k_8dSX6MSE2pO_ZYHkey0KRLSjuwzkZ5DV0ly3ZG2iDG0keZN4vgm/s1600/ds5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6_tCo2Rj70dFM3kTWbDQjpz8oVYrzMs-yz1SiPOH_PnHvCZ11AYV6Qngsur9HuiuNVomNKe_nH2BWjMoH6AYuao6k_8dSX6MSE2pO_ZYHkey0KRLSjuwzkZ5DV0ly3ZG2iDG0keZN4vgm/s1600/ds5.png" /></a></div>
<br />
<br />
La classe concreta <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000012z000000.htm" target="_blank">RouteMeasureLocatorName</a> è mostrato nella seguente illustrazione:
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM8F7V3fEuPEQLm2LYKgXtWPmdnyWU5M3E28WFVixe6HQ23xRPHiKchGI8sLy7YNRlTnWTZS725zbs7iGJRjIdZ-RuhC74VzdRpJoCRaD1v0EYmgdgLKEcexqVp74PXmQd9cJgYRzXu1i9/s1600/ds6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM8F7V3fEuPEQLm2LYKgXtWPmdnyWU5M3E28WFVixe6HQ23xRPHiKchGI8sLy7YNRlTnWTZS725zbs7iGJRjIdZ-RuhC74VzdRpJoCRaD1v0EYmgdgLKEcexqVp74PXmQd9cJgYRzXu1i9/s1600/ds6.png" /></a></div>
<br />
<br />
L’interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000007v8000000.htm" target="_blank">IRouteLocatorName</a> è utilizzata per restituire le proprietà di un oggetto RouteLocator.
<br />
<br />
Il <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/003100000120000000.htm" target="_blank">LocatorName</a> è una classe astratta che può essere utilizzata per far riferimento ad un oggetto Locator. <br />
Il RouteLocatorName è una classe astratta che può essere utilizzata per riferirsi ad un oggetto RouteLocator. <br />
<a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000012z000000.htm" target="_blank">RouteMeasureLocatorName</a> è una classe concreta che può essere utilizzata per riferirsi ad un oggetto RouteMeasureLocator ed è una specifica implementazione del <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/003100000120000000.htm" target="_blank">LocatorName</a> e del RouteLocatorName.
<br />
Tutte le classi di <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000012z000000.htm" target="_blank">RouteLocatorName</a> implementano l’interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000007v8000000.htm" target="_blank">IRouteLocatorName</a>. Tale interfaccia si usa per impostare e restituire le proprietà dell’oggetto RouteLocatorName (classe concreta: RouteMeasureLocatorName). <br />
<br />
Seguono alcune precisazioni circa le proprietà di questa interfaccia:<br />
<br />
<ul>
<li><a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000007v9000000.htm" target="_blank">RouteFeatureClassName</a>: feature class polyline con valori m. </li>
<li><a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000007vm000000.htm" target="_blank">RouteIDFieldName</a>: qualsiasi campo numerico o testuale contenente l’identificatore di route. Questo campo si relazionerà ad un campo della stessa natura nella tabella eventi. </li>
<li><a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000007vp000000.htm" target="_blank">RouteMeasureUnit</a>: unità di misura dei valori m memorizzati nelle route. Il valore di default è <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0042/004200000030000000.htm" target="_blank">esriUnknownUnits</a>. </li>
<li><a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0025/0025000007vq000000.htm" target="_blank">RouteWhereClause</a>: condizione che limita il noumero di routes sulle quali le posizioni possono essere trovate. </li>
</ul>
<br />
Il seguente esempio di codice mostra come creare un RouteMeasureLocator via RouteMeasureLocatorName:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: #2b91af;"> IDataset</span> dS = (<span style="color: #2b91af;">IDataset</span>)routeFC; <span style="color: green;">// A polylineM feature class.</span>
<span style="color: #2b91af;">IName</span> name = dS.FullName;
<span style="color: #2b91af;">IRouteLocatorName</span> rtLocatorName = <span style="color: blue;">new</span> <span style="color: #2b91af;">RouteMeasureLocatorNameClass</span>();
rtLocatorName.RouteFeatureClassName = name;
rtLocatorName.RouteIDFieldName = <span style="color: #a31515;">"routeId"</span>;
rtLocatorName.RouteMeasureUnit = <span style="color: #2b91af;">esriUnits</span>.esriMeters;
name = (<span style="color: #2b91af;">IName</span>)rtLocatorName;
<span style="color: #2b91af;">IRouteLocator2</span> rtLocator = (<span style="color: #2b91af;">IRouteLocator2</span>)name.Open();</pre>
<br />
Una RouteMeasureLocation descrive una porzione di route o una singola posizione lungo una route.
L’interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/0031000000t8000000.htm" target="_blank">IRouteLocation</a> ti permette di definire le proprietà di una posizione route, ad esempio le posizioni route che si trovano lungo una singola route; perciò, impostane qui il valore. In aggiunta, identifica le unità di misura nelle quali la posizione route è stata raccolta e specifica se lo desideri che la shape della posizione di route abbia un offset dalla route quando è posizionata.
<br />
<br />
Gli offset sono nelle unità di misura del riferimento spaziale della route feature class (e non necessariamente nelle stesse unità delle misure della feature class). Quindi, un offset su dati di route memorizzati in unità geografiche potrebbe produrre risultati non corretti. Gli offset vengono utilizzati esclusivamente per scopi di visualizzazione degli eventi sulla mappa.
<br />
<br />
Impostare la proprietà <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/0031000000tp000000.htm">IRouteLocation.MeasureUnit</a><span id="goog_400713997"></span><a href="http://www.blogger.com/"></a><span id="goog_400713998"></span> ti consente di eseguire al volo conversioni di misure. Tale proprietà corrisponde a IRouteLocatorName.RouteMeasureUnit. Ad esempio, potresti conoscere la collocazione di una posizione route in miglia, ma la tua route feature class ha le sue misure memorizzate in metri. Impostando i valori di conseguenza, puoi ottenere la conversione della misura. <br />
<br />
<a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000012t000000.htm">RouteMeasureLineLocation</a> è una classe che descrive porzioni di una route utilizzando posizioni di misura DA - A. L’oggetto <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000012t000000.htm">RouteMeasureLineLocation</a> è mostrato nella seguente illustrazione:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3f5LtFjQ3m8-OFVLe5TURRyT9mtbQFeOt-Bav092gi5f06cccUApYLa3451d1FifxbkejJCbFZaloC9-6SDismpV2a-Kz9zkAywlJGTW-Wr8e3elWqhzxRxESMvtY77hbdwSATzYZO_Hx/s1600/ds7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3f5LtFjQ3m8-OFVLe5TURRyT9mtbQFeOt-Bav092gi5f06cccUApYLa3451d1FifxbkejJCbFZaloC9-6SDismpV2a-Kz9zkAywlJGTW-Wr8e3elWqhzxRxESMvtY77hbdwSATzYZO_Hx/s1600/ds7.png" /></a></div>
<br />
<br />
L’interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/003100000107000000.htm" target="_blank">IRouteMeasureLineLocation</a> è dove puoi impostare i valori di misura Da – A delle posizioni route, ad esempio, trovare una posizione a partire da 2500 metri a 3500 metri lungo la route 10 e impostare un offset di 25 metri dalla route:
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: #2b91af;"> IRouteLocation</span> routeLoc = <span style="color: blue;">new</span> <span style="color: #2b91af;">RouteMeasureLineLocationClass</span>();
routeLoc.MeasureUnit = <span style="color: #2b91af;">esriUnits</span>.esriMeters;
routeLoc.RouteID = 10;
routeLoc.LateralOffset = 25;
<span style="color: #2b91af;">IRouteMeasureLineLocation</span> rMLineLoc = (<span style="color: #2b91af;">IRouteMeasureLineLocation</span>)routeLoc;
rMLineLoc.FromMeasure = 2500;
rMLineLoc.ToMeasure = 3500;</pre>
<br />
<a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/003100000130000000.htm" target="_blank">RouteMeasurePointLocation</a> è una classe che utilizza un singolo valore di m per rappresentare una singola posizione lungo la route.
<br />
<br />
L’interfaccia <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/00310000010q000000.htm" target="_blank">IRouteMeasurePointLocation</a> è dove puoi impostare i valori m delle posizioni. Ad esempio per trovare la posizione a 565.5 metri lungo la route 10:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"> <span style="color: #2b91af;">IRouteLocation</span> routeLocation = <span style="color: blue;">new</span> <span style="color: #2b91af;">RouteMeasurePointLocationClass</span>();
routeLocation.MeasureUnit = <span style="color: #2b91af;">esriUnits</span>.esriMeters;
routeLocation.RouteID = 10;
routeLocation.LateralOffset = 0;
<span style="color: #2b91af;">IRouteMeasurePointLocation</span> rMPointLoc = (<span style="color: #2b91af;">IRouteMeasurePointLocation</span>)routeLocation;
rMPointLoc.Measure = 565.5;</pre>
<br />
Una volta che hai creato la posizione di route, determini la sua geometria chiamando il metodo IRouteLocator.Locate come mostrato nel seguente codice di esempio:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: #2b91af;"> IGeometry</span> geom;
<span style="color: #2b91af;">esriLocatingError</span> locError;
rtLocator.Locate((<span style="color: #2b91af;">IRouteLocation</span>)rMPointLoc, <span style="color: blue;">out</span> geom, <span style="color: blue;">out</span> locError);</pre>
<br />
<a href="http://www.arcgis.com/home/item.html?id=e3bfa7c991e34aa8872c937ca9169507" target="_blank">Qui</a> potete scaricare una SOE (10 e 10.1) che ho sviluppato che permette interrogare la M lungo una route, impostare una posizione puntuale e lineare via rest mediante un servizio ArcGIS Server, utilizzando i metodi qui presentati.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/z2SIF5sIii0?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
Anche ESRI ha sviluppato una SOE che potete trovare <a href="http://www.arcgis.com/home/item.html?id=2ccd7d9d70cf4284b41e45859d2870a0" target="_blank">qui</a> tra i samples di arcgis.com. Una volta disegnata la polyline la SOE posiziona i marker ogni miglia o chilometro. In questo caso la creazione della route è fatta al volo impostando i valori di m con la lunghezza cumulata a partire dall'origine della geometria (il parametro <em>ratio</em> = false indica che si vuole il valore assoluto delle m e non quello relativo rispetto alla lunghezza complessiva della polyline).<br />
<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: #2b91af;"> IMSegmentation</span> mSeg = (<span style="color: #2b91af;">IMSegmentation</span>)pointColl;
mSeg.SetMsAsDistance(<span style="color: blue;">false</span>);</pre>
<br />
<br />
<div style="text-align: center;">
<iframe height="700" seamless="seamless" src="http://servicesbeta.esri.com/demos/milemarker/milemarker.html" width="700"></iframe><br /></div>
<br />
<br />
Per dettagli su come impostare le route event source lineari e puntuali (come già detto: feature class dinamiche basate su tabelle eventi), come creare route, come calibrare le misure route, come geoprocessare eventi, come localizzare feature lungo le route e come etichettare le feature lineari con m (hatching) seguite il seguente <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/0031/003100000138000000.htm" target="_blank">link</a>.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902194 9.256010800000012820.068184900000002 -32.052583199999987 71.1122539 50.564604800000012tag:blogger.com,1999:blog-8323071861123024882.post-59593629498567455532012-11-17T19:45:00.000+01:002012-11-28T20:04:25.704+01:00Smack...! Bacini idrograficiL’extension Spatial Analyst, una delle più utilizzate in ArcGIS, permette un’innumerevole serie di analisi. Tra queste troviamo anche quelle relative all’idrologia. In questo caso, ArcGIS ci mette a disposizione uno strumento per lo sviluppo di soluzioni e la gestione delle risorse idriche. Gli idrologi e gli idrogeologi possono utilizzare la tecnologia GIS per integrare vari tipi di dati e applicazioni in un unico sistema centralizzato. L’insieme degli strumenti contenuti, ad esempio, in <a href="http://support.esri.com/en/downloads/datamodel/detail/15" target="_blank">ArcHydro</a>, facilita la creazione, la gestione e la visualizzazione degli oggetti idrologici all’interno dell’ambiente di ArcGIS.<br />
I seguenti tool ci sono messi a disposizione per la gestione delle nostre analisi: Basin, Fill, Flow Accumulation, Flow Direction, Flow Length, Sink, Snap Pour Point, Stream Link, Stream Order, Stream To Feature e Watershed <br />
E’ possibile, ad esempio, con questi tool delineare in modo automatico il bacino imbrifero a partire dal modello digitale del terreno, determinare il reticolo idrografico e l’ordine delle aste fluviali.<br />
Ad esempio, per determinare un bacino idrografico a partire da una sezione di chiusura, si procede creando innanzitutto un raster che rappresenta la direzione di flusso di ogni cella ad una delle otto celle adiacenti verso la quale ha la pendenza maggiore. A seconda delle direzione la cella sarà impostata con i valori 1,2,4,8,16,32,64 o 128.<br />
I valori di output sono derivati da una rappresentazione binaria dei risultati dell’analisi e, come possiamo osservare dall’immagine, se il flusso è diretto a destra verrà impostato 1, se il flusso è diretto in basso a destra verrà impostato 2 e così via fino a 128. Il focal flow che è un filtro focale può utilizzare operatori bitwise; così, ad esempio, se da una cella il flusso è in tutte le direzioni verrà impostato il valore 128+64+32+16+8+4+2+1 = 255, mentre se dovesse essere nella direzione 3 e 1 sarà 4+1 = 5.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF8o-PInuQek4Nm0sHTGrKSey5KJ7vjYKv_XsYGnAt0bbWTde8pmSZZbxwW5Ux5QCnESm49oCpOQyryFUlTtJ26D5tyuESxECjxXPjVIn5LnZDcFBG9xUvr3MCpkMXrGumYE77-c3mQMEq/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF8o-PInuQek4Nm0sHTGrKSey5KJ7vjYKv_XsYGnAt0bbWTde8pmSZZbxwW5Ux5QCnESm49oCpOQyryFUlTtJ26D5tyuESxECjxXPjVIn5LnZDcFBG9xUvr3MCpkMXrGumYE77-c3mQMEq/s640/1.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAJ3s9eSlcjYGwwxgMnrVDQjQA-pk9ekGFXkAvKLTGbwD1m9M9Tlf16tJ02bkdosvnBVo1rD1fCiBsy2xX9mrJFDB7scka7HsTacWXYHlOD99z2yTkW6D9sHmLY1JYBDvJhyC0oOBNVCLs/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAJ3s9eSlcjYGwwxgMnrVDQjQA-pk9ekGFXkAvKLTGbwD1m9M9Tlf16tJ02bkdosvnBVo1rD1fCiBsy2xX9mrJFDB7scka7HsTacWXYHlOD99z2yTkW6D9sHmLY1JYBDvJhyC0oOBNVCLs/s640/2.png" width="640" /></a></div>
<div align="justify" class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
L’approccio utilizzato è quello di un modello di flusso di otto direzioni (D8) e segue l’approccio presentato da Jensen and Domingue (1988).</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
Il calcolo effettuato per determinare la direzione con la pendenza più ripida per ogni cella è:<br />
<span style="font-size: medium;"></span><br />
<span style="font-size: medium;"></span><br />
<span style="font-size: medium;"></span><br />
<span style="font-size: medium;"></span><br />
<span style="font-size: medium;"><div style="text-align: center;">
ΔZ / distanza</div>
</span><br />
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
La distanza è deteminata tra i centri delle celle, pertanto la cella centrale rispetto alle celle poste sulla diagonale avrà un fattore 1,4142.. (le celle sono quadrate) mentre le altre avranno un fattore 1.</div>
Nell’esempio seguente la dimensione della cella è 1 unità.<br />
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe4SuX2Dtp-lrGDs-UsJiwojcGFeN74GhqfF7NzaFhzvWolHGws35Xi9AXIXt9Qe7VrkzD41F9W4F_u_9ZPkwEQGZP3a-3Ps8VILjWlT7L-T-1yuVk5fWD4tWZ5QRfhQVDf5Mjpb0gE1Oc/s1600/3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="408" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe4SuX2Dtp-lrGDs-UsJiwojcGFeN74GhqfF7NzaFhzvWolHGws35Xi9AXIXt9Qe7VrkzD41F9W4F_u_9ZPkwEQGZP3a-3Ps8VILjWlT7L-T-1yuVk5fWD4tWZ5QRfhQVDf5Mjpb0gE1Oc/s640/3.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
Se tutte le celle adiacenti sono più alte di quella centrale, la cella è un sink (pozzo) ed avrà una direzione di flusso non definita. Celle con direzione di flusso non definito possono essere marcate come sink utilizzando la funzione Sink. Per ottenere una rappresentazione accurata della direzione di flusso sulla superficie, i sink possono essere riempiti con la funzione Fill utilizzando il DEM.<br />
Una volta determinata la direzione di flusso a partire dal DEM, occorre determinare gli accumuli di flusso. La flow accumulation è determinata a partire dalla flow direction.<br />
Questa funzione calcola il flusso accumulato come peso accumulato di tutte le celle che scorrono verso ogni cella. Se non è fornito un peso sul raster, ad ogni cella è applicato un peso pari a 1 e quindi il numero rappresentato sarà il numero di celle nel quale il flusso arriva alla cella.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjPc0dxbNteOsSTkYE1H75eZIJMUfD6VuylCPxPIpN8jhAgamZumK5NO4MzqJHp84OS2JxSPusn5eqV7BvfGDt4JwomkZmNkG5jSCVXpKIh5XhWhvIN8GhMIvXfG44GYcVuVsIO-OO-1Og/s1600/4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjPc0dxbNteOsSTkYE1H75eZIJMUfD6VuylCPxPIpN8jhAgamZumK5NO4MzqJHp84OS2JxSPusn5eqV7BvfGDt4JwomkZmNkG5jSCVXpKIh5XhWhvIN8GhMIvXfG44GYcVuVsIO-OO-1Og/s640/4.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
In questo esempio è stato dato peso 1 ad ogni cella.</div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjErAZDoTQn_ol3zhm5rcchXQYQP7h3920d2imk6astrZNGBnXNTbw7pixRfnUgwK6t3p43DdFhGzKQIAEgptHTcRpQtSqHABE4XbyBIfTj8SntruiDvpWFm3JtAdZe5DvaRCdnFEMI_Cyq/s1600/5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="464" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjErAZDoTQn_ol3zhm5rcchXQYQP7h3920d2imk6astrZNGBnXNTbw7pixRfnUgwK6t3p43DdFhGzKQIAEgptHTcRpQtSqHABE4XbyBIfTj8SntruiDvpWFm3JtAdZe5DvaRCdnFEMI_Cyq/s640/5.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
Celle con un elevato accumulo di flusso sono aree dove l’acqua converge in modo massiccio e possono essere utilizzate per identificare canali di flusso, mentre celle con accumulo di flusso pari a zero possono essere utilizzate per identificare gli spartiacque.</div>
Un esempio di utilizzo di un raster pesato nella funzione di Flow Accumulation è determinare l’ammontare di pioggia caduta all’interno di un dato bacino imbrifero. In questo caso il raster pesato potrebbe essere un raster che rappresenta la precipitazione media durante un dato temporale. Il risultato della funzione di Flow Accumulation rappresenterà la quantità di pioggia che defluisce in ogni cella, assumendo che tutta la pioggia defluisce senza altri fattori che possano influenzarla (evapotraspirazione, infiltrazione nel sottosuolo ecc.).<br />
Ora, per determinare i bacini idrografici relativi a determinate sezioni di chiusura, possiamo utilizzare la funzione Watershed che richiede come input la flow direction e i punti rappresentanti le sezione di chiusura.<br />
Il modello seguente determina un watershed a partire da una flow direction, una flow accumulation e da uno o più punti che si posizioneranno mediante la distanza di snap alle celle con il più alto valore di flusso di accumulo (Snap Pour Point).<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioMny2GNG8_nvkrnvahaZUIkZEXo4-fOwHZ-bmpS0-zYXdRJ-RgPy2nlxaGliPPlA-NnqXQVL4tYYKalGYTF7cgvaVuW5ipAeaZZcDl1KS6IwUa0NIlCENtTZLY3xoLePJ8_9d3urHSpHo/s1600/6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioMny2GNG8_nvkrnvahaZUIkZEXo4-fOwHZ-bmpS0-zYXdRJ-RgPy2nlxaGliPPlA-NnqXQVL4tYYKalGYTF7cgvaVuW5ipAeaZZcDl1KS6IwUa0NIlCENtTZLY3xoLePJ8_9d3urHSpHo/s640/6.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: justify;">
Utilizzando gli ArcObjects, l’interfaccia da utilizzare è la <a href="http://resources.arcgis.com/en/help/arcobjects-net/componenthelp/index.html#/IHydrologyOp2_Interface/0040000000t5000000/" target="_blank">IHydrologyOp2</a> della library Spatial Analyst che ci mette a disposizione tutte le funzioni elencate precedentemente.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
Per determinare un watershed scriveremo:<br />
<br />
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: blue;"> try</span>
{
<span style="color: #2b91af;">IFeatureWorkspace</span> featureWorkspace = <span style="color: #2b91af;">Helper</span>.CreateInMemoryWorkspace() <span style="color: blue;">as</span> <span style="color: #2b91af;">IFeatureWorkspace</span>;
<span style="color: #2b91af;">IFeatureClass</span> featureClass = <span style="color: blue;">this</span>.CreateFeatureClass(location, featureWorkspace);
<span style="color: #2b91af;">IFeature</span> feature = featureClass.CreateFeature();
feature.Shape = location;
feature.set_Value(featureClass.FindField(<span style="color: #2b91af;">SAUtility</span>.FieldNameIdWatershed), (<span style="color: blue;">int</span>)idWatershed.Value);
feature.Store();
<span style="color: #2b91af;">IHydrologyOp</span> hydrologyOp = <span style="color: blue;">new</span> <span style="color: #2b91af;">RasterHydrologyOp</span>() <span style="color: blue;">as</span> <span style="color: #2b91af;">IHydrologyOp</span>;
<span style="color: #2b91af;">IGeoDataset</span> accumulation = <span style="color: blue;">this</span>.GetGeodataset((<span style="color: blue;">int</span>)idAccumulation.Value);
<span style="color: #2b91af;">IGeoDataset</span> direction = <span style="color: blue;">this</span>.GetGeodataset((<span style="color: blue;">int</span>)idDirection.Value);
<span style="color: #2b91af;">IFeatureClassDescriptor</span> featureClassDescriptor = <span style="color: blue;">new</span> <span style="color: #2b91af;">FeatureClassDescriptorClass</span>();
featureClassDescriptor.Create(featureClass, <span style="color: blue;">null</span>, <span style="color: #2b91af;">SAUtility</span>.FieldNameIdWatershed);
<span style="color: #2b91af;">IGeoDataset</span> pourPoint = featureClassDescriptor <span style="color: blue;">as</span> <span style="color: #2b91af;">IGeoDataset</span>;
<span style="color: #2b91af;">IRasterAnalysisEnvironment</span> rasterAnalysisEnvironment = <span style="color: blue;">new</span> <span style="color: #2b91af;">RasterAnalysisClass</span>();
<span style="color: blue;">object</span> extentProvider = <span style="color: #2b91af;">Type</span>.Missing;
<span style="color: blue;">object</span> snapRasterData = <span style="color: #2b91af;">Type</span>.Missing;
rasterAnalysisEnvironment.SetExtent(<span style="color: #2b91af;">esriRasterEnvSettingEnum</span>.esriRasterEnvMaxOf, <span style="color: blue;">ref</span> extentProvider, <span style="color: blue;">ref</span> snapRasterData);
<span style="color: #2b91af;">IGeoDataset</span> snapRaster = hydrologyOp.SnapPourPoint(pourPoint, accumulation, snapDistance.Value);
<span style="color: #2b91af;">IGeoDataset</span> watershed = hydrologyOp.Watershed(direction, snapRaster);
<span style="color: #2b91af;">IConversionOp</span> conversionOp = <span style="color: blue;">new</span> <span style="color: #2b91af;">RasterConversionOpClass</span>() <span style="color: blue;">as</span> <span style="color: #2b91af;">IConversionOp</span>;
<span style="color: #2b91af;">IGeoDataset</span> featureClassWatershed = conversionOp.RasterDataToPolygonFeatureData(watershed, featureWorkspace <span style="color: blue;">as</span> <span style="color: #2b91af;">IWorkspace</span>, <span style="color: #a31515;">"WatershedPolygon"</span>, <span style="color: blue;">true</span>);
<span style="color: #2b91af;">IRecordSetInit</span> recordset = <span style="color: blue;">new</span> <span style="color: #2b91af;">RecordSetClass</span>();
recordset.SetSourceTable(featureClassWatershed <span style="color: blue;">as</span> <span style="color: #2b91af;">ITable</span>, <span style="color: blue;">null</span>);
<span style="color: blue;">byte</span>[] recorset = <span style="color: #2b91af;">Conversion</span>.ToJson(recordset <span style="color: blue;">as</span> <span style="color: #2b91af;">IRecordSet</span>);
<span style="color: blue;">this</span>.logger.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.infoDetailed, methodName, <span style="color: #2b91af;">SAUtility</span>.MessageCodeSOE, <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"Watershed created with succcess. IdWatershed {0}"</span>, (<span style="color: blue;">int</span>)idWatershed.Value));
<span style="color: blue;">return</span> recorset;
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ex)
{
<span style="color: blue;">this</span>.logger.LogMessage(<span style="color: #2b91af;">ServerLogger</span>.<span style="color: #2b91af;">msgType</span>.error, methodName, <span style="color: #2b91af;">SAUtility</span>.MessageCodeSOE, ex.Message);
<span style="color: blue;">return</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">ObjectError</span>(<span style="color: #a31515;">"error create watershed"</span>).ToJsonObject().JsonByte();
}</pre>
<br />
Per puro divertimento (come dice il mio amico Erik) ho creato una SOE da utilizzate in ArcGIS Server 10.1 per poter creare bacini idrografici online.
Potete scaricarla <a href="http://studioat.maps.arcgis.com/home/item.html?id=7b79eea8286e462bba9b2891b42d223a" target="_blank">qui</a>.<br />
<br />
<div style="text-align:center;">
<iframe src="http://sit.sistemigis.it/Samples/Watershed" seamless="seamless" width ="700" height="700"></iframe></div>
<br />
<br />
Per i non sviluppatori gli stessi risultati possono essere ottenuti pubblicando il modello (che potete scaricare <a href="http://www.arcgis.com/home/item.html?id=6987d0a0daa14fe9861bae93e4808845" target="_blank">qui</a> mentre il tutorial lo trovate <a href="http://resources.arcgis.com/en/help/main/10.1/0154/015400000333000000.htm" target="_blank">qui</a>) visto precedentemente.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902194 9.256010845.5888304 9.2535433 45.591608400000005 9.2584783tag:blogger.com,1999:blog-8323071861123024882.post-5664536590549592332012-10-11T15:22:00.001+02:002012-10-11T22:51:12.898+02:00ArcGIS for Server 10.1: RESTful administrative API<div style="text-align: justify;">
ArcGIS for Server espone via <a href="http://it.wikipedia.org/wiki/Representational_State_Transfer" target="_blank">Rest</a> <a href="http://resources.arcgis.com/en/help/server-admin-api/" target="_blank">API</a> per l'amministrazione. Questo significa che possiamo gestire completamente il nostro server creando tool che fanno richieste http.</div>
<div style="text-align: justify;">
Le <a href="http://resources.arcgis.com/en/help/server-admin-api/" target="_blank">API</a> sono organizzate in <em>Resources</em> e <em>Operations: </em>le resource sono entità in ArcGIS for Server che hanno delle informazioni ed uno stato ben definito, mentre le operation si attuano ed aggiornano le informazioni o lo stato delle resource. Le resource e le operation sono gerarchiche ed hanno un URL univoco.</div>
<div style="text-align: justify;">
Le <a href="http://resources.arcgis.com/en/help/server-admin-api/" target="_blank">API</a> per l'amministrazione supportano l'autenticazione basata su token. Per utilizzare le <a href="http://resources.arcgis.com/en/help/server-admin-api/" target="_blank">API</a> occorre fornire un token che sia stato acquisito fornendo credenziali amministrative. Ovviamente, data la natura delle informazione trasmesse tra le <a href="http://resources.arcgis.com/en/help/server-admin-api/" target="_blank">API</a> per l'amministrazione e l'utente delle stesse, la comunicazione dovrebbe avvenire su una connessione SSL.<br />
Per poter utilizzare le <a href="http://resources.arcgis.com/en/help/server-admin-api/" target="_blank">API</a> per l'amministrazione occorre essere un PSA (Primary Site Administrator) o avere privilegi amministrativi.</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
ESRI ha già pubblicato dei <a href="http://www.arcgis.com/home/item.html?id=12dde73e0e784e47818162b4d41ee340" target="_blank">tool</a> utlizzando Python, ma nulla vieta di utilizzare il linguaggio a noi più familiare (Java, JavaScript, PowerShell, C#, Ruby, Scala, Perl, ecc.).</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
<a href="http://resources.arcgis.com/en/help/main/10.1/0154/0154000005p3000000.htm" target="_blank">Qui</a> potete trovare la guida in linea che descrive tramite esempi le varie funzionalità delle API.</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
Interessante notare come sia possibile registrare macchine e aggiungere, unire ed eliminare site; ciò permette, schedulando task, di distribuire un numero maggiore di istanze su più macchine se le richieste ai servizi dovessero aumentare. Ma possiamo anche semplicemente schedulare lo stato di salute dei nostri servizi ed inviare un'email se ci sono dei problemi od esaminare le statistiche per un determinato servizio.</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
Alcune delle operazioni di amministrazione possono richiedere un po' di tempo. Per prevenire il blocco del client mentre l'operazione è in esecuzione, è possibile eseguire queste operazioni in modalità asincrona passando come parametro alla richiesta <em>runAsync</em> uguale a <strong>true. </strong>A questo punto, il sistema risponderà con un jobID e il client dovrà seguire l'esecuzione dalla resource <em>jobs </em>ed attendere che lo status sia <strong><em>COMPLETED</em></strong> per avere la response dell'operazione.</div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
Qui vediamo un esempio utilizzando c#:<br />
</div>
<pre style="background: white; color: black; font-family: Consolas;"><span style="color: blue;">namespace</span> Studioat.ArcGIS.Server.Administrator
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> Studioat.ArcGIS.Rest;
<span style="color: blue;">class</span> <span style="color: #2b91af;">Program</span>
{
<span style="color: blue;">static</span> <span style="color: blue;">void</span> Main(<span style="color: blue;">string</span>[] args)
{
<span style="color: #2b91af;">AGSAdmin</span> agsAdmin = <span style="color: blue;">new</span> <span style="color: #2b91af;">AGSAdmin</span>(<span style="color: #a31515;">"myserver"</span>, 6080, <span style="color: #a31515;">"admin"</span>, <span style="color: #a31515;">"secret"</span>);
<span style="color: blue;">string</span> serviceName = <span style="color: #a31515;">"SampleWorldCities"</span>;
<span style="color: blue;">bool</span> result = agsAdmin.StopService(serviceName, <span style="color: #2b91af;">ServiceType</span>.MapServer);
<span style="color: #2b91af;">Console</span>.WriteLine(<span style="color: #a31515;">"stop service {0}, result: {1}"</span>, serviceName, result);
<span style="color: green;">//string serviceName = "SampleWorldCities";</span>
result = agsAdmin.StartService(serviceName, <span style="color: #2b91af;">ServiceType</span>.MapServer);
<span style="color: #2b91af;">Console</span>.WriteLine(<span style="color: #a31515;">"stop service {0}, result: {1}"</span>, serviceName, result);
<span style="color: blue;">string</span> folder = <span style="color: #a31515;">"Demo1"</span>;
result = agsAdmin.CreateServerFolder(folder, <span style="color: #a31515;">"Prova 1"</span>);
<span style="color: #2b91af;">Console</span>.WriteLine(<span style="color: #a31515;">"create folder {0}, result: {1}"</span>, folder, result);
<span style="color: blue;">string</span> physicalPath;
<span style="color: blue;">string</span> virtualPath;
result = agsAdmin.GetServerDirectory(<span style="color: #a31515;">"arcgisoutput"</span>, <span style="color: blue;">out</span> physicalPath, <span style="color: blue;">out</span> virtualPath);
<span style="color: #2b91af;">Console</span>.WriteLine(<span style="color: #a31515;">"physicalPath {0}, virtualPath {1}, result: {2}"</span>, physicalPath, virtualPath, result);
agsAdmin.ListServices();
<span style="color: #2b91af;">Console</span>.Read();
agsAdmin.CreateService();
}
}
}
<span style="color: blue;">namespace</span> Studioat.ArcGIS.Rest
{
<span style="color: blue;">using</span> System;
<span style="color: blue;">using</span> System.Collections;
<span style="color: blue;">using</span> System.Collections.Generic;
<span style="color: blue;">using</span> System.IO;
<span style="color: blue;">using</span> System.Linq;
<span style="color: blue;">using</span> System.Net;
<span style="color: blue;">using</span> System.Text;
<span style="color: blue;">using</span> System.Web;
<span style="color: blue;">using</span> ESRI.ArcGIS.SOESupport;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> tipi di servizio arcgis server (mappa la tabella servizio tipo)</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">enum</span> <span style="color: #2b91af;">ServiceType</span>
{
MapServer,
GeocodeServer,
SearchServer,
IndexingLauncher,
IndexGenerator,
GeometryServer,
GeoDataServer,
GPServer,
GlobeServer,
ImageServer
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Load Balancing</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">enum</span> <span style="color: #2b91af;">LoadBalancing</span>
{
ROUND_ROBIN,
FAIL_OVER
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> isolation level</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">enum</span> <span style="color: #2b91af;">IsolationLevel</span>
{
LOW,
HIGH
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> administrative API Rest</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">AGSAdmin</span>
{
<span style="color: blue;">private</span> <span style="color: blue;">string</span> username;
<span style="color: blue;">private</span> <span style="color: blue;">string</span> password;
<span style="color: blue;">private</span> <span style="color: blue;">string</span> urlRestAdmin;
<span style="color: blue;">private</span> <span style="color: blue;">string</span> urlRestServer;
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Initializes a new instance of the </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"AGSAdmin"</span><span style="color: grey;">/></span><span style="color: green;"> class.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"serverName"</span><span style="color: grey;">></span><span style="color: green;">server name</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"port"</span><span style="color: grey;">></span><span style="color: green;">port of server</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"username"</span><span style="color: grey;">></span><span style="color: green;">username administrator</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"password"</span><span style="color: grey;">></span><span style="color: green;">password administrator</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> AGSAdmin(<span style="color: blue;">string</span> serverName, <span style="color: blue;">int</span> port, <span style="color: blue;">string</span> username, <span style="color: blue;">string</span> password)
{
<span style="color: blue;">this</span>.username = username;
<span style="color: blue;">this</span>.password = password;
<span style="color: blue;">string</span> url = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"http://{0}:{1}/arcgis"</span>, serverName, port.ToString());
<span style="color: blue;">this</span>.urlRestAdmin = url + <span style="color: #a31515;">"/admin"</span>;
<span style="color: blue;">this</span>.urlRestServer = url + <span style="color: #a31515;">"/server"</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Prevents a default instance of the </span><span style="color: grey;"><see cref=</span><span style="color: grey;">"AGSAdmin"</span><span style="color: grey;">/></span><span style="color: green;"> class from being created.</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">private</span> AGSAdmin()
{
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Create arcgis server folder</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"folderName"</span><span style="color: grey;">></span><span style="color: green;">Folder name</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"description"</span><span style="color: grey;">></span><span style="color: green;">Description of the folder</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">True if successfully created</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> CreateServerFolder(<span style="color: blue;">string</span> folderName, <span style="color: blue;">string</span> description)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> token = <span style="color: blue;">this</span>.GenerateAGSToken();
<span style="color: blue;">string</span> folderUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/services/"</span> + folderName + <span style="color: #a31515;">"?f=json&token="</span> + token;
<span style="color: blue;">string</span> resultExistsFolder = <span style="color: blue;">this</span>.GetResult(folderUrl);
<span style="color: blue;">if</span> (!<span style="color: blue;">this</span>.HasError(resultExistsFolder))
{
<span style="color: blue;">return</span> <span style="color: blue;">true</span>; <span style="color: green;">// exists</span>
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">string</span> createFolderUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/services/createFolder"</span>;
<span style="color: blue;">string</span> postContent = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"folderName={0}&description={1}&f=json&token={2}"</span>, folderName, description, token);
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(createFolderUrl, postContent);
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.HasSuccess(result);
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Get physical Path and virtual Path from directory ags</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"directory"</span><span style="color: grey;">></span><span style="color: green;">directory ags</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"physicalPath"</span><span style="color: grey;">></span><span style="color: green;">physical Path</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"virtualPath"</span><span style="color: grey;">></span><span style="color: green;">virtual Path</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">True if successfully return path</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> GetServerDirectory(<span style="color: blue;">string</span> directory, <span style="color: blue;">out</span> <span style="color: blue;">string</span> physicalPath, <span style="color: blue;">out</span> <span style="color: blue;">string</span> virtualPath)
{
physicalPath = <span style="color: blue;">null</span>;
virtualPath = <span style="color: blue;">null</span>;
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> token = <span style="color: blue;">this</span>.GenerateAGSToken();
<span style="color: blue;">string</span> directoryUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/system/directories/"</span> + directory + <span style="color: #a31515;">"?f=json&token="</span> + token;
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(directoryUrl);
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>(result);
<span style="color: blue;">if</span> (!jsonObject.Exists(<span style="color: #a31515;">"physicalPath"</span>) || !jsonObject.TryGetString(<span style="color: #a31515;">"physicalPath"</span>, <span style="color: blue;">out</span> physicalPath))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">Exception</span>();
}
jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>(result);
<span style="color: blue;">if</span> (!jsonObject.Exists(<span style="color: #a31515;">"virtualPath"</span>) || !jsonObject.TryGetString(<span style="color: #a31515;">"virtualPath"</span>, <span style="color: blue;">out</span> virtualPath))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">Exception</span>();
}
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Delete Service</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"serviceName"</span><span style="color: grey;">></span><span style="color: green;">Service Name</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"serviceType"</span><span style="color: grey;">></span><span style="color: green;">Server Type</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">True if successfully deleted</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> DeleteService(<span style="color: blue;">string</span> serviceName, <span style="color: #2b91af;">ServiceType</span> serviceType)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> token = <span style="color: blue;">this</span>.GenerateAGSToken();
<span style="color: blue;">string</span> serviceUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/services/"</span> + serviceName + <span style="color: #a31515;">"."</span> + <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ServiceType</span>), serviceType) + <span style="color: #a31515;">"/delete"</span>;
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(serviceUrl, <span style="color: #a31515;">"f=json&token="</span> + token);
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.HasSuccess(result);
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Start Service</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"serviceName"</span><span style="color: grey;">></span><span style="color: green;">Service Name</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"serviceType"</span><span style="color: grey;">></span><span style="color: green;">Server Type</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">True if successfully started</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> StartService(<span style="color: blue;">string</span> serviceName, <span style="color: #2b91af;">ServiceType</span> serviceType)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> token = <span style="color: blue;">this</span>.GenerateAGSToken();
<span style="color: blue;">string</span> serviceUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/services/"</span> + serviceName + <span style="color: #a31515;">"."</span> + <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ServiceType</span>), serviceType) + <span style="color: #a31515;">"/start"</span>;
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(serviceUrl, <span style="color: #a31515;">"f=json&token="</span> + token);
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.HasSuccess(result);
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Stop Service</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"serviceName"</span><span style="color: grey;">></span><span style="color: green;">Service Name</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"serviceType"</span><span style="color: grey;">></span><span style="color: green;">Server Type</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">True if successfully stopped</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> StopService(<span style="color: blue;">string</span> serviceName, <span style="color: #2b91af;">ServiceType</span> serviceType)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> token = <span style="color: blue;">this</span>.GenerateAGSToken();
<span style="color: blue;">string</span> serviceUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/services/"</span> + serviceName + <span style="color: #a31515;">"."</span> + <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ServiceType</span>), serviceType) + <span style="color: #a31515;">"/stop"</span>;
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(serviceUrl, <span style="color: #a31515;">"f=json&token="</span> + token);
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.HasSuccess(result);
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> list of services</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">public</span> <span style="color: blue;">void</span> ListServices()
{
<span style="color: blue;">this</span>.ListServices(<span style="color: blue;">null</span>);
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> list of services in folder</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"folder"</span><span style="color: grey;">></span><span style="color: green;">name of folder</span><span style="color: grey;"></param></span>
<span style="color: blue;">public</span> <span style="color: blue;">void</span> ListServices(<span style="color: blue;">string</span> folder)
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> token = <span style="color: blue;">this</span>.GenerateAGSToken();
<span style="color: blue;">string</span> serviceUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/services/"</span> + folder;
<span style="color: blue;">string</span> postcontent = <span style="color: #a31515;">"f=json&token="</span> + token;
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(serviceUrl, postcontent);
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>(result);
<span style="color: blue;">object</span>[] folders = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (jsonObject.Exists(<span style="color: #a31515;">"folders"</span>) && jsonObject.TryGetArray(<span style="color: #a31515;">"folders"</span>, <span style="color: blue;">out</span> folders))
{
<span style="color: blue;">foreach</span> (<span style="color: blue;">string</span> subfolder <span style="color: blue;">in</span> folders)
{
<span style="color: blue;">this</span>.ListServices(subfolder);
}
}
<span style="color: blue;">object</span>[] services = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (jsonObject.Exists(<span style="color: #a31515;">"services"</span>) && jsonObject.TryGetArray(<span style="color: #a31515;">"services"</span>, <span style="color: blue;">out</span> services))
{
<span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">JsonObject</span>> jsonObjectService = services.Cast<<span style="color: #2b91af;">JsonObject</span>>();
jsonObjectService.ToList().ForEach(jo =>
{
<span style="color: blue;">string</span> serviceName;
jo.TryGetString(<span style="color: #a31515;">"serviceName"</span>, <span style="color: blue;">out</span> serviceName);
<span style="color: blue;">string</span> folderName;
jo.TryGetString(<span style="color: #a31515;">"folderName"</span>, <span style="color: blue;">out</span> folderName);
<span style="color: #2b91af;">Console</span>.WriteLine(folderName + <span style="color: #a31515;">"/"</span> + serviceName);
});
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> create service type MapServer</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">>True if successfully created</span><span style="color: grey;"></returns></span>
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> CreateService()
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> token = <span style="color: blue;">this</span>.GenerateAGSToken();
<span style="color: blue;">string</span> serviceUrl = <span style="color: blue;">this</span>.urlRestAdmin + <span style="color: #a31515;">"/services/createService"</span>;
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
jsonObject.AddString(<span style="color: #a31515;">"serviceName"</span>, <span style="color: #a31515;">"Test"</span>);
jsonObject.AddString(<span style="color: #a31515;">"type"</span>, <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">ServiceType</span>), <span style="color: #2b91af;">ServiceType</span>.MapServer));
jsonObject.AddString(<span style="color: #a31515;">"description"</span>, <span style="color: #a31515;">"This is an example"</span>);
jsonObject.AddString(<span style="color: #a31515;">"capabilities"</span>, <span style="color: #a31515;">"Map,Query,Data"</span>);
jsonObject.AddString(<span style="color: #a31515;">"clusterName"</span>, <span style="color: #a31515;">"default"</span>);
jsonObject.AddLong(<span style="color: #a31515;">"minInstancesPerNode"</span>, 1);
jsonObject.AddLong(<span style="color: #a31515;">"maxInstancesPerNode"</span>, 2);
jsonObject.AddLong(<span style="color: #a31515;">"maxWaitTime"</span>, 60);
jsonObject.AddLong(<span style="color: #a31515;">"maxStartupTime"</span>, 300);
jsonObject.AddLong(<span style="color: #a31515;">"maxIdleTime"</span>, 1800);
jsonObject.AddLong(<span style="color: #a31515;">"maxUsageTime"</span>, 600);
jsonObject.AddLong(<span style="color: #a31515;">"recycleInterval"</span>, 24);
jsonObject.AddString(<span style="color: #a31515;">"loadBalancing"</span>, <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">LoadBalancing</span>), <span style="color: #2b91af;">LoadBalancing</span>.ROUND_ROBIN));
jsonObject.AddString(<span style="color: #a31515;">"isolationLevel"</span>, <span style="color: #2b91af;">Enum</span>.GetName(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">IsolationLevel</span>), <span style="color: #2b91af;">IsolationLevel</span>.HIGH));
<span style="color: #2b91af;">JsonObject</span> jsonObjectProperties = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>();
<span style="color: green;">// see for a list complete http://resources.arcgis.com/en/help/server-admin-api/serviceTypes.html</span>
jsonObjectProperties.AddLong(<span style="color: #a31515;">"maxBufferCount"</span>, 100); <span style="color: green;">// optional 100</span>
jsonObjectProperties.AddString(<span style="color: #a31515;">"virtualCacheDir"</span>, <span style="color: blue;">this</span>.urlRestServer + <span style="color: #a31515;">"/arcgiscache"</span>); <span style="color: green;">// optional</span>
jsonObjectProperties.AddLong(<span style="color: #a31515;">"maxImageHeight"</span>, 2048); <span style="color: green;">// optional 2048</span>
jsonObjectProperties.AddLong(<span style="color: #a31515;">"maxRecordCount"</span>, 1000); <span style="color: green;">// optional 500</span>
<span style="color: green;">// Starting at ArcGIS 10.1, Map Server Definition ( .msd ) files have been</span>
<span style="color: green;">// replaced with Service Definition Draft ( .sddraft ) and Service Definition ( .sd ) files. </span>
<span style="color: green;">// In the case of a map service, you must specify a map service definition (MSD) file in your JSON. </span>
<span style="color: green;">// This file synthesizes information from your ArcMap document (MXD) in a format that can be understood and </span>
<span style="color: green;">// drawn by ArcGIS Server. You must use the arcpy.mapping module to analyze your map and create the MSD before </span>
<span style="color: green;">// you can go ahead with creating the service. This part requires a machine licensed for ArcGIS for Desktop. </span>
<span style="color: green;">// Other service types do not require you to use arcpy.mapping or create an MSD.</span>
jsonObjectProperties.AddString(<span style="color: #a31515;">"filePath"</span>, <span style="color: #a31515;">@"C:\AvGis\Test\mappa\UTM_ReteFognaria.msd"</span>); <span style="color: green;">// required</span>
jsonObjectProperties.AddLong(<span style="color: #a31515;">"maxImageWidth"</span>, 2048); <span style="color: green;">// optional 2048</span>
jsonObjectProperties.AddBoolean(<span style="color: #a31515;">"cacheOnDemand"</span>, <span style="color: blue;">false</span>); <span style="color: green;">// optional false</span>
jsonObjectProperties.AddString(<span style="color: #a31515;">"virtualOutputDir"</span>, <span style="color: blue;">this</span>.urlRestServer + <span style="color: #a31515;">"/arcgisoutput"</span>);
jsonObjectProperties.AddString(<span style="color: #a31515;">"outputDir"</span>, <span style="color: #a31515;">@"C:\arcgisserver\directories\arcgisoutput"</span>); <span style="color: green;">// required</span>
jsonObjectProperties.AddString(<span style="color: #a31515;">"supportedImageReturnTypes"</span>, <span style="color: #a31515;">"MIME+URL"</span>); <span style="color: green;">// optional MIME+URL</span>
jsonObjectProperties.AddBoolean(<span style="color: #a31515;">"isCached"</span>, <span style="color: blue;">false</span>); <span style="color: green;">// optional false</span>
jsonObjectProperties.AddBoolean(<span style="color: #a31515;">"ignoreCache"</span>, <span style="color: blue;">false</span>); <span style="color: green;">// optional false </span>
jsonObjectProperties.AddBoolean(<span style="color: #a31515;">"clientCachingAllowed"</span>, <span style="color: blue;">false</span>); <span style="color: green;">// optional true </span>
jsonObjectProperties.AddString(<span style="color: #a31515;">"cacheDir"</span>, <span style="color: #a31515;">@"C:\arcgisserver\directories\arcgiscache"</span>); <span style="color: green;">// optional</span>
jsonObject.AddJsonObject(<span style="color: #a31515;">"properties"</span>, jsonObjectProperties);
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(serviceUrl, <span style="color: #a31515;">"service="</span> + <span style="color: #2b91af;">HttpUtility</span>.UrlEncode(jsonObject.ToJson()) + <span style="color: #a31515;">"&f=json&token="</span> + token);
<span style="color: blue;">return</span> <span style="color: blue;">this</span>.HasSuccess(result);
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> check is status is equal success</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"result"</span><span style="color: grey;">></span><span style="color: green;">result of request</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">True if status is equal success</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> HasSuccess(<span style="color: blue;">string</span> result)
{
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>(result);
<span style="color: blue;">string</span> status = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (!jsonObject.Exists(<span style="color: #a31515;">"status"</span>) || !jsonObject.TryGetString(<span style="color: #a31515;">"status"</span>, <span style="color: blue;">out</span> status))
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">return</span> status == <span style="color: #a31515;">"success"</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> check is status is equal error</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"result"</span><span style="color: grey;">></span><span style="color: green;">result of request</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">True if status is equal error</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> HasError(<span style="color: blue;">string</span> result)
{
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>(result);
<span style="color: blue;">string</span> status = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (!jsonObject.Exists(<span style="color: #a31515;">"status"</span>) || !jsonObject.TryGetString(<span style="color: #a31515;">"status"</span>, <span style="color: blue;">out</span> status))
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">return</span> status == <span style="color: #a31515;">"error"</span>;
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Get request rest</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"url"</span><span style="color: grey;">></span><span style="color: green;">url of request</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">return response</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> GetResult(<span style="color: blue;">string</span> url)
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">WebRequest</span> request = <span style="color: #2b91af;">WebRequest</span>.Create(url);
<span style="color: #2b91af;">WebResponse</span> response = request.GetResponse();
<span style="color: blue;">using</span> (<span style="color: #2b91af;">Stream</span> responseStream = response.GetResponseStream())
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">StreamReader</span> reader = <span style="color: blue;">new</span> <span style="color: #2b91af;">StreamReader</span>(responseStream))
{
<span style="color: blue;">return</span> reader.ReadToEnd();
}
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Post request rest</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"url"</span><span style="color: grey;">></span><span style="color: green;">url of request</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><param name=</span><span style="color: grey;">"postContent"</span><span style="color: grey;">></span><span style="color: green;">content of post</span><span style="color: grey;"></param></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">return response</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> GetResult(<span style="color: blue;">string</span> url, <span style="color: blue;">string</span> postContent)
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">WebRequest</span> request = <span style="color: #2b91af;">WebRequest</span>.Create(url);
<span style="color: blue;">byte</span>[] content = <span style="color: #2b91af;">Encoding</span>.UTF8.GetBytes(postContent);
request.ContentLength = content.Length;
request.ContentType = <span style="color: #a31515;">"application/x-www-form-urlencoded"</span>;
request.Method = <span style="color: #2b91af;">WebRequestMethods</span>.<span style="color: #2b91af;">Http</span>.Post;
<span style="color: blue;">using</span> (<span style="color: #2b91af;">Stream</span> requestStream = request.GetRequestStream())
{
requestStream.Write(content, 0, content.Length);
requestStream.Close();
<span style="color: #2b91af;">WebResponse</span> response = request.GetResponse();
<span style="color: blue;">using</span> (<span style="color: #2b91af;">Stream</span> responseStream = response.GetResponseStream())
{
<span style="color: blue;">using</span> (<span style="color: #2b91af;">StreamReader</span> reader = <span style="color: blue;">new</span> <span style="color: #2b91af;">StreamReader</span>(responseStream))
{
<span style="color: blue;">return</span> reader.ReadToEnd();
}
}
}
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">throw</span>;
}
}
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> Generate a token</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><returns></span><span style="color: green;">A token that has default expiration time</span><span style="color: grey;"></returns></span>
<span style="color: blue;">private</span> <span style="color: blue;">string</span> GenerateAGSToken()
{
<span style="color: blue;">try</span>
{
<span style="color: blue;">string</span> urlGenerateToken = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"{0}/generateToken"</span>, <span style="color: blue;">this</span>.urlRestAdmin);
<span style="color: blue;">string</span> credential = <span style="color: blue;">string</span>.Format(<span style="color: #a31515;">"username={0}&password={1}&client=requestip&expiration=&f=json"</span>, <span style="color: blue;">this</span>.username, <span style="color: blue;">this</span>.password);
<span style="color: blue;">string</span> result = <span style="color: blue;">this</span>.GetResult(urlGenerateToken, credential);
<span style="color: #2b91af;">JsonObject</span> jsonObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">JsonObject</span>(result);
<span style="color: blue;">string</span> token = <span style="color: blue;">null</span>;
<span style="color: blue;">if</span> (!jsonObject.Exists(<span style="color: #a31515;">"token"</span>) || !jsonObject.TryGetString(<span style="color: #a31515;">"token"</span>, <span style="color: blue;">out</span> token))
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> <span style="color: #2b91af;">Exception</span>(<span style="color: #a31515;">"Token not found!"</span>);
}
<span style="color: blue;">return</span> token;
}
<span style="color: blue;">catch</span>
{
<span style="color: blue;">return</span> <span style="color: blue;">string</span>.Empty;
}
}
}
}
</pre>
Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com1Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902194 9.256010845.5888304 9.2535433 45.591608400000005 9.2584783tag:blogger.com,1999:blog-8323071861123024882.post-74999278648162633602012-09-29T21:45:00.000+02:002012-10-01T18:28:52.953+02:00ArcGIS 10.1 & .NET 4.0Con la nuova versione ArcGIS 10.1 possiamo ora sviluppare utilizzando anche il .NET framework 4.0. Il .NET 3.5 SP1 rimane la versione minima richiesta per poter sviluppare in ambiente .NET con ArcGIS 10.1. Difatti il .NET 3.5 SP1 è un prerequisito per installare ArcGIS Desktop o per ArcGIS Engine per Windows.<br />
Però ora è possibile utilizzare e sviluppare appoggiandosi anche a .NET 4.0 Framework. E' chiaro che occorrerà in aggiunta al 3.5SP1 installare anche il framework 4.0 perchè quest'ultimo non include la versione 3.5.<br />
Se la nostra applicazione richiede funzionalità presenti solo nel Framework 4.0, possiamo estendere i prodotti ESRI con componenti scritte nel Framework 4.0. In questo caso dovremo verificare nella distribuzione della nostra applicazione che il framework sia installato sul sistema di destinazione.<br />
Per poter 'debuggare' il nostro add-in o il nostro componente personalizzato con ArcGIS Desktop, lo sviluppatore deve modificare lo specifico file di configurazione (ArcMap, ArcCatalog ecc.) sulla propria macchina per aggiungere il supporto per il runtime .NET 4.0, oppure in alternativa è possibile agganciare il processo attraverso Visual Studio.<br />
Ad esempio, se uno sviluppatore crea un add-in con .NET 4.0 per ArcMap, per eseguire il debug dovrà modificare il file <strong>ArcMap.exe.config</strong> posizionato nella cartella bin di ArcGIS Desktop. Questa configurazione specifica i CLR che sono supportati con l'applicazione e redirige gli assembly per consentire ai componenti più vecchi di essere testati nella versione corrente di ArcGIS. Nel file di configurazione dell'applicazione dovresti vedere le seguenti informazioni XML:<br />
<br />
<span style="color: #741b47;"><span class="kwrd"><span style="color: blue;"><</span></span><span class="html">startup</span></span><span class="kwrd"><span style="background-color: white; color: blue;">></span></span><br />
<span class="rem"><span style="color: #38761d;"><!--<supportedRuntime version="v4.0.30319"/>--></span></span><br />
<span class="kwrd"><span style="color: blue;"><</span></span><span class="html"><span style="color: #741b47;">supportedRuntime</span></span> <span class="attr"><span style="color: red;">version</span></span><span style="color: blue;"><span class="kwrd">="v2.0.50727"</span><span class="kwrd">/></span></span><br />
<span style="color: #741b47;"><span class="kwrd"><span style="color: blue;"></</span></span><span class="html">startup</span></span><span style="color: blue;"><span class="kwrd">></span></span><br />
<br />
Per abilitare il debug occorre rimuovere il commento per l'elemento <supportedRuntime> della versione 4.0<br />
<br />
Si sottolinea però il fatto che, poichè gli add-in .NET non richiedono un particolare setup per la distribuzione poichè possono essere installati semplicemente con un doppio click o utilizzando l'add-in Manager, non c'è modo di verificare che la macchina di destinazione abbia il .NET framework installato prima dell'installazione dell'add-in. Di conseguenza, se utilizziamo il framework 4.0, potenzialmente potremmo limitare l'utilizzo del nostro add-in ad alcuni utenti se non hanno installato il framework 4.0.<br />
<br />
Se il nostro add-in utilizza il framework 3.5 non dobbiamo invece preoccuparci di nulla perchè il .NET 3.5 SP1 è, come detto, richiesto da ArcGIS for Desktop e ArcGIS Engine per Windows.<br />
<br />
<br />
Le precedenti versioni del .NET Framework possono essere installate nella stessa macchina, ma solo una versione del framework può essere caricata in un processo. Questo causò problemi di compatibilità con soluzioni sviluppate utilizzando il più vecchio framework (Microsoft ovviò a questo creando i framework 3.0 e 3.5 ancora basati sul CLR della versione 2.0 e quindi mantenendo la retrocompatibilità con le applicazioni scritte per la versione 2.0).<br />
Diversamente dalle precedenti versioni del .NET framework, una caratteristica del .NET Framework 4.0 consente di coesistere nello stesso processo con il .NET Framework 2.0 (<a href="http://msdn.microsoft.com/en-us/library/ee518876.aspx" target="_blank">In-Process Side-by-Side</a>). Questo significa che un processo può utilizzare entrambe le versioni del framework contemporaneamente. Di conseguenza, componenti COM e codice gestito 3.5 Framework gireranno in Framework 3.5 consentendo di sfruttare le nuove funzionalità .NET Framemork 4.0 senza doversi preoccupare di problemi di compatibilità con la nuova versione del framework.<br />
<br />
L'Embed Interop Types è una nuova caratteristica del .NET Framework 4.0 che consente di includere le informazione degli attributi che sono normalmente memorizzate nell'assembly di interoperabilità primario (PIA) nell'eseguibile o nella dll. Questo è stato fatto perchè la distribuzione di soluzioni gestite sviluppate su certe tecnologie basate su COM era difficoltosa poichè la distribuzione e la verifica del PIA erano anche fatte sulla macchina di destinazione.<br />
<br />
Un Assembly di interoperabilità primario (PIA) contiene la descrizione ufficiale dei tipi come definiti dal pubblicatore dei tipi. Un assembly di interoperabilità primario è un assembly che contiene un insieme di classi wrapper firmato che consente di chiamare codice non gestito da codice gestito.<br />
Un assembly di interoperabilità primario è un assembly univoco fornito dal produttore che contiene le definizioni di tipo dei tipi che sono implementati utilizzando il modello COM. In un assembly di interoperabilità primario sono contenute le definizioni dei tipi come metadati. Il pubblicatore di libreria di tipo COM deve firmare solo un assembly di interoperabilità primario con un nome sicuro. Un singolo PIA può disporre di più versioni della stessa libreria dei tipi.<br />
Una libreria dei tipi COM che viene importata come un assembly e che è firmata da un pubblicatore diverso dal pubblicatore della libreria di tipi originale non può essere un assembly di interoperabilità primario. Solo il pubblicatore della libreria dei tipi può creare un assembly di interoperabilità primario che diventa l'unità di definizioni di tipo ufficiale per l'interoperabilità con i tipi COM sottostanti.<br />
<br />
In modo predefinito, quando si aggiunge un PIA in un progetto Visual Studio .NET 4.0 senza utilizzare il plug-in <em>Add ArcGIS Reference</em>, la proprietà Embed Interop Types della PIA è impostata a <em><strong>true.</strong></em> La best practice è cambiare l'impostazione a <strong><em>false</em></strong> quando si distribuisce la personalizzazione di ArcGIS, perchè l'installer di ArcGIS imposta gli appropriati PIA e assembly nel sistema, pertanto non si dovrebbe includere nella propria soluzione.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha5tH8eRvh4tcGSeUzes0RLY3eO8U2PFdrnRcBcUe9ZYwBSQd_kYgEgv-09LXGCytGPUPupp7lRIyonVcw0wvZFgL-o3z5-_PWqGNz3-xIrXln4vxtBhrg6ANzUXBf6X0dJVhS_Lrqo9_w/s1600/ao-net4_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="361" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha5tH8eRvh4tcGSeUzes0RLY3eO8U2PFdrnRcBcUe9ZYwBSQd_kYgEgv-09LXGCytGPUPupp7lRIyonVcw0wvZFgL-o3z5-_PWqGNz3-xIrXln4vxtBhrg6ANzUXBf6X0dJVhS_Lrqo9_w/s640/ao-net4_1.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUV-X2H1rDvP0MgwjxvNw_Tcw5Hn-zdbaIuKvYqiWXlAdnz8I1WQtnkLJs81irzoMJCDfc02cICox5TjwmkZMbOn98DaXZ3sdd8Eq9bnMKHO96CvkELv_lQ_Q-8ZJ-jsnKdHKD0ncfgtGk/s1600/ao-net4_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUV-X2H1rDvP0MgwjxvNw_Tcw5Hn-zdbaIuKvYqiWXlAdnz8I1WQtnkLJs81irzoMJCDfc02cICox5TjwmkZMbOn98DaXZ3sdd8Eq9bnMKHO96CvkELv_lQ_Q-8ZJ-jsnKdHKD0ncfgtGk/s640/ao-net4_2.png" width="640" /></a></div>
<br />
Nella versione 10.1 ArcGIS for Server è un'applicazione nativa a 64bit mentre ArcGIS for Desktop e ArcGIS Engine rimangono a 32bit (x86). Di conseguenza, i PIA sono ripristinati al loro precedente stato MSIL (Microsoft Intermediate Language). Questo consente agli stessi assembly di essere usati in entrambi gli ambienti: 32bit per ArcGIS for Desktop e ArcGIS Engine e 64bit per ArcGIS for Server.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.5902194 9.256010845.5888304 9.2535433 45.591608400000005 9.2584783tag:blogger.com,1999:blog-8323071861123024882.post-47949116443636171902012-08-31T21:13:00.000+02:002012-09-16T21:28:55.803+02:00ArcGIS 10.1: ce n'è per tutti!ArcGIS 10.1 include funzionalità aggiuntive e miglioramenti su tutta la linea di prodotti ArcGIS.<br />
<div>
Diversi prodotti hanno cambiato il nome nella 10.1. Una lista parziale dei nome cambiati dei prodotti la potete trovare in <a href="http://www.esri.com/news/arcnews/summer11articles/a-note-about-names.html" target="_blank">ArcNews</a>.</div>
<div>
Le seguenti sezioni sintetizzano i cambiamenti del software nelle differenti aree funzionali. Ogni sezione include collegamenti ad argomenti con maggiori dettagli per la specifica area del software.</div>
<div>
</div>
<h3>
<span style="color: blue;">Mapping</span></h3>
<h4>
<span style="color: red;"><div>
Elementi base in ArcMap</div>
</span><div>
</div>
</h4>
<ul>
<li>Nuovo modo di selezionare il sistema di coordinate. E’ possibile ricercare il riferimento spaziale per nome, per wkid (factory code) e per estensione spaziale;</li>
<li>le trasformazioni di datum composte possono essere create nell’interfaccia utente;</li>
<li>il renderer dot density ora include la possibilità di indicare il seed per il posizionamento dei punti. Abbiamo una nuova opzione che consente di scegliere come modalità di gestione della densità tra dimensione del punto o valore del punto;</li>
<li>sono supportati nuovi tipi di layer per i layer basemap di ArcMap ( <a href="http://blogs.esri.com/esri/arcgis/2010/02/02/basemap-layers-new-at-arcgis-10/" target="_blank">Base Map Layer</a> )</li>
</ul>
<div>
o Dot density layers</div>
<div>
o Dimension layer</div>
<div>
o TIN and terrain layers</div>
<div>
o Schematics layer</div>
<div>
o Geostatistical layers—contours e filled contours</div>
<div>
o XY event layers</div>
<div>
o Linear referencing event layers</div>
<ul>
<li>python ora è supportato come linguaggio di scripting in tutte le parti dove è previsto l’utilizzo dello scripting: espressioni per etichette, espressioni nel display expression, script per hyperlink, dimension e hatching per riferimenti lineari;</li>
<li>sono ora disponibili i credits per i layer di servizi.</li>
</ul>
<div>
Per maggiori dettagli sulle novità visitare il link <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000002w000000.htm" target="_blank">elementi base di ArcMap 10.1</a></div>
<div>
</div>
<h4>
<span style="color: red;">Testo ed etichettamento</span></h4>
<div>
<br />
La funzionalità dell’estensione Maplex di ArcGIS è stata inglobata nel core del prodotto ArcGIS Desktop ed è indicata come Maplex Label Engine. In sintesi elenchiamo le nuove funzionalità di etichettamento, annotation e Maplex Label Engine:</div>
<ul>
<li>migliorato il supporto internazionale per la visualizzazione di testo di script complessi (ad esempio Arabo, Ebraico e Tailandese);</li>
<li>in ArcMap l’engine predefinito per l’etichettamento è il Maplex Label Engine;</li>
<li>i parametri per il posizionamento globale dell’etichetta per il controllo della connessione di linee e per i poligoni multipart sono stati spostati dalle opzioni di Maplex label a livello di classe di label consentendo quindi un controllo più fine (a livello di classe) che di dataframe;</li>
<li>aggiunta la possibilità di controllare gli spazi vuoti e quindi rimuoverli all’interno di testo etichettato, opzione aggiunta nella finestra di dialogo <strong><em>Label Expression</em></strong>;</li>
<li>è stata aggiunta una nuova linguetta <strong>Label Density</strong> nella finestra di dialogo <strong><em>Placement Properties</em></strong> per organizzare i parametri che influenzano la densità delle etichette;</li>
<li>è stata aggiunta la numerazione a chiave come metodo per gestire le etichette molte ravvicinate;</li>
<li>è stata aggiunta un’opzione nello stile del Regular Placement per supportare l’etichettamento delle linee su entrambi i lati della feature quando l’etichetta è su più righe e si posiziona l’etichetta con l’offset;</li>
<li>è stata aggiunta un’opzione per ripetere le etichette delle linee per consentire di averle vicino a punti di congiungimento o ai bordi della mappa;</li>
<li>nel parametro di troncamento sono state aggiunte delle opzioni per controllare quali caratteri eliminare preliminarmente, la minima lunghezza per parola e il carattere marker (carattere finale per le abbreviazioni);</li>
<li>è stata aggiunta un’opzione al parametro point label offset per consentire di indicare un offset dall’outline del simbolo;</li>
<li>lo Street Placement è stato migliorato per includere il parametro connessione di linea;</li>
<li>l’opzione di linea dello Standard Label Engine (one per feature, one per feature part e per feature segment) è stato aggiunto al parametro connessione di linea;</li>
<li>il parametro per espandere le parole può anche essere applicato alle etichette dei poligoni.</li>
</ul>
<div>
Per maggiori dettagli sulle novità visitare il link <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000002n000000.htm" target="_blank">What's new in Maplex for ArcGIS 10.1</a></div>
<div>
</div>
<h4>
<span style="color: red;">Simboli e stili</span><div>
</div>
</h4>
<div>
In sintesi elenchiamo le nuove funzionalità per i simboli e gli stili:</div>
<div>
<ul>
<li>i formati GIF, PNG e JPEG sono supportati per i simboli picture;</li>
<li>le regole e i marker di rappresentazione memorizzati in uno stile supportano i tag per la ricerca;</li>
<li>le regole e i marker di rappresentazione in ESRI.style, C2 Military Operations.style e Military METOC.style sono stati compilati con tag di ricerca che indicano la composizione e il colore di rappresentazione;</li>
<li>quando una versione localizzata di ArcGIS è installata, saranno installati versioni localizzate di stili di uso comune. Questi stili saranno utilizzati da ArcGIS piuttosto che quelli della versione in inglese.</li>
</ul>
<div>
</div>
</div>
<h4>
<span style="color: red;">Rappresentazioni</span><div>
</div>
</h4>
<div>
In sintesi elenchiamo le nuove funzionalità per le rappresentazioni:</div>
<div>
<ul>
<li>ArcGIS 10.1 introduce tre nuovi effetti geometrici per le linee: Extension, Offset tangent e Suppress;</li>
<li>gli stili per la rappresentazione del posizionamento dei marker è stato aggiornato dando la possibilità di aggiungere/togliere il senso orario di rotazione;</li>
<li>regole e marker di rappresentazione memorizzate in uno stile supportano i tag per la ricerca.</li>
</ul>
<div>
Per maggiori dettagli sulle novità visitare il link <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000003v000000.htm" target="_blank">What's new for representations in ArcGIS 10.1</a></div>
</div>
<div>
</div>
<h4>
<span style="color: red;">Page layout e data frame</span><div>
</div>
</h4>
<div>
In sintesi elenchiamo le nuove funzionalità per page layout e data frame:</div>
<div>
<ul>
<li>la legenda è stata migliorata: ora è dinamica. In pratica, le legende supportano la visualizzazione solo delle feature presenti nella corrente estensione con conteggio delle stesse. Inoltre, le legende possono avere un’area fissata sulla pagina. La dimensione del frame rimarrà fissa e, come le voci di legenda sono aggiunte o rimosse, le stesse saranno disposte per riempirlo;</li>
<li>è stata aggiunta una nuova opzione nel True North per migliorare la calibrazione dell’angolo;</li>
<li>la scale bar è stata migliorata: ora consente di impostare il punto zero come ancoraggio così che scale bar multiple con differenti unità possano essere allineate con le altre.</li>
</ul>
<div>
Per maggiori dettagli sulle novità visitare il link <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000027000000.htm" target="_blank">What's new for page layout and data frames in ArcGIS 10.1</a>.</div>
<div>
</div>
</div>
<h4>
<span style="color: red;">Esportazione a PDF</span><div>
</div>
</h4>
<div>
In sintesi elenchiamo le nuove funzionalità l’esportazione in PDF:</div>
<div>
<ul>
<li>ArcGIS ora supporta l’esportazione di PDF protetti da password dall’interfaccia utente in ArcMap. Nella versione 10.0, la protezione di PDF con password era solo possibile con Python. Nella versione 10.1, è possibile utilizzare la linguetta <strong>Security</strong> nelle opzioni della finestra di dialogo <strong><em>Map Export</em></strong> impostando la password per l’apertura del documento e per altre impostazioni per la sicurezza del PDF.</li>
</ul>
<div>
Per maggiori dettagli sulle novità visitare il link <a href="http://resources.arcgis.com/en/help/main/10.1/00sm/00sm00000007000000.htm" target="_blank">Exporting to PDF</a>.</div>
</div>
<div>
</div>
<h4>
<span style="color: red;">Automazione dei flussi di lavoro di mappe</span></h4>
<div>
</div>
<div>
In sintesi elenchiamo le nuove funzionalità per l’automazione di flussi di lavoro di mappe:<br />
<ul>
<li>Ormai si possono automatizzare le proprietà di simbologia per le seguenti voci: colori graduati, simboli graduati, valori unici e raster classificati.</li>
<li>E’ disponibile una funzione report di esportazione, che consente di automatizzare le generazioni di report.</li>
<li>ArcGIS 10.1 fornisce l’accesso alle proprietà temporali di un layer in modo da eseguire l’analisi temporale. Si può inoltre abilitare il tempo sui layer.</li>
<li>Si sono apportati ulteriori miglioramenti al mapping di arcpy, compresa l’impostazione della dimensione testuale, l’impostazione dei percorsi relativi e la dimensione della pagina di lettura.</li>
</ul>
<div>
Per maggiori dettagli sulle novità nell’automazione dei flussi di lavoro di mappe, vedere <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000027000000.htm" target="_blank">What’s new for automating map workflows in ArcGIS 10.1</a>.</div>
</div>
<div>
</div>
<h4>
<span style="color: red;">Generalizzazione cartografica ed individuazione dei conflitti dei simboli</span></h4>
<div>
<div>
<br />
Ciò che segue sintetizza le nuove funzionalità per la generalizzazione cartografica e l’individuazione dei conflitti dei simboli.</div>
</div>
<ul>
<li>Molti strumenti per la soluzione di conflitti di generalizzazione e grafica nel <a href="http://resources.arcgis.com/en/help/main/10.1/0070/007000000003000000.htm" target="_blank">Cartography toolbox</a> sono ora abilitati alla divisione per consentire loro di processare dataset molto più vasti. La divisione sotto-separa dinamicamente i dati in entrata per essere processati, assicurando un risultato uniforme in uscita.</li>
<li>Sono stati introdotti nuovi strumenti di geoprocessing che supportano i flussi di lavoro per processare le feature di strade ed edifici per essere visualizzate meglio alle piccole scala.</li>
</ul>
<div>
Vedere <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000004v000000.htm" target="_blank">What's new for the Cartography toolbox</a> per ulteriori informazioni.</div>
<div>
</div>
<h4>
<span style="color: red;">Condivisione di mappe e dati</span><div>
</div>
</h4>
<div>
Ciò che segue sintetizza le nuove funzionalità per la condivisione di mappe e dati:</div>
<div>
<ul>
<li>ArcGIS for Desktop offre una nuova modalità unificata di pubblicazione.</li>
<li>Si possono creare pacchetti di GP task e di Address locator da ArcGIS for Desktop.</li>
</ul>
<div>
Vedere <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000003p000000.htm" target="_blank">What's new for sharing maps and data in ArcGIS 10.1</a> per ulteriori informazioni.</div>
</div>
<div>
</div>
<h4>
<span style="color: red;">Ricerca sul desktop</span><div>
</div>
</h4>
<div>
In ArcGIS 10.1, miglioramenti significativi sono stati raggiunti per cercare il proprio contenuto GIS:</div>
<ul>
<li>Supporto di ricerca spaziale: la finestra di ricerca supporta una gran varietà di modi per cercare spazialmente il contenuto GIS.</li>
</ul>
- Supporto di ricerca spaziale basato sulla mappa.<br />
- Supporto di ricerca spaziale basato sul testo.<br />
- Supporto di ricerca spaziale basato sulla scala.<br />
<ul>
<li>La finestra di ricerca ora supporta l'ordinamento ed il raggruppamento dei risultati della propria ricerca, così è possibile rapidamente esaminare un numero ristretto di risultati.</li>
<li>Supporto sinonimi.</li>
<li>Migliore esecuzione di indicizzazione ed inoltre capacità di loggare dati danneggiati e saltarli in fase di indice.</li>
<li>Diversi miglioramenti sono stati fatti sull'aspetto dei risultati della ricerca, compresa la possibilità di mostrare un’immagine di anteprima per ogni risultato, abilitato un context menu su ogni elemento nei risultati della ricerca ed altro ancora.</li>
</ul>
<div>
Per saperne di più, vedere <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000055000000.htm" target="_blank">What's new in the ArcGIS for Desktop search</a>.</div>
<div>
</div>
<h4>
<span style="color: red;">Dati temporali</span><div>
</div>
</h4>
<div>
Riassumiamo qui le nuove funzionalità per i dati temporali:</div>
<div>
<ul>
<li>Time slider supporta la visualizzazione degli aggiornamenti più recenti dei dati temporali usando la modalità live.</li>
<li>La finestra temporale sul time slider può essere configurata per mostrare o nascondere i dati temporali che cadono esattamente all’inizio o alla fine di una specifica finestra temporale.</li>
<li>E' possibile inglobare il tempo come testo quando si esportano immagini o video di una visualizzazione temporale dalla data view in ArcMap, ArcScene, o ArcGlobe.</li>
</ul>
<div>
Vedere <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000039000000.htm" target="_blank">What's new for temporal data in ArcGIS 10.1</a> per ulteriori dettagli.</div>
</div>
<div>
</div>
<h4>
<span style="color: red;">Report</span> <div>
</div>
</h4>
<div>
Riassumiamo qui le nuove funzionalità per i report:</div>
<ul>
<li>Puoi creare un report usando feature visibili di un dato layer scegliendo l’opzione Visible Extent for the Dataset.</li>
<li>Ora è possibile generare un report che include i dati related del source layer.</li>
<li>E’ disponibile la funzione di esportazione di un report che ti permette di automatizzare la generazione di report.</li>
</ul>
Per saperne di più, vedere <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000002z000000.htm" target="_blank">What's new for Reports in ArcGIS 10.1</a><br />
<br />
<br />
<h3>
<span style="color: blue;">GESTIONE DEI DATI</span></h3>
<h4>
<div>
<span style="color: red;">Database</span></div>
</h4>
<div>
</div>
<br />
Le seguenti funzionalità sono novità in ArcGIS 10.1 for Desktop per lavorare con i database:<br />
<div>
</div>
<ul>
<li>La modificata finestra di dialogo <strong><em>Database Connections</em></strong> ed il tool di geoprocessing Create Database Connections ti permettono di connetterti ad un database supportato da ArcGIS for Desktop e di visualizzare i dati.</li>
<li>Puoi installare il data type ST_Geometry in un database Oracle o PostgreSQL usando il tool di geoprocessing Create Spatial Type.</li>
<li>Puoi usare il tool Create Database User per aggiungere un utente ad Oracle, PostgreSQL, o SQL Server. Agli utenti sono garantiti privilegi sufficienti a creare oggetti per il database. In SQL Serve, gli utenti hanno anche privilegi sufficienti a leggere tabelle di sistema contenenti liste di login e ruoli del database. In Oracle, vengono creati con abbastanza privilegi da leggere la tabella di sistema dei ruoli del database.</li>
<li>Puoi creare un ruolo del database in Oracle, PostgreSQL, o SQL Server utilizzando il tool di geoprocessing Create Role. Inoltre puoi utilizzare questo tool per aggiungere utenti ai ruoli.</li>
<li>Da ArcGIS for Desktop, puoi creare tabelle e feature class in un database e caricarci i dati.</li>
<li>Puoi aggiungere, eliminare o rinominare campi nelle tabelle del database.</li>
<li>Puoi rinominare le tabelle del database.</li>
<li>Puoi eliminare tabelle dal database.</li>
<li>Puoi creare viste dalle tabelle del database usando il tool di geoprocessing Create Database View.</li>
<li>Puoi ricostruire gli indici sulle tabelle dei database esistenti usando il tool di geoprocessing Rebuild Indexes.</li>
<li>Puoi usare Analyze Dataset per aggiornare le statistiche delle tabelle del database ed i loro indici associati.</li>
<li>Un nuovo tipo di server— ArcGIS Spatial Data Server—è disponibile per fornire le geometrie, gli attribute, i simboli e le informazioni su template per i dati di vettoriali che sono memorizzati come tabelle nei database abilitati alla componente spaziale DB2, SQL Server, Oracle o PostgreSQL.</li>
<li>Puoi usare il tool di geoprocessing Add Incrementing ID Field per aggiungere ad una tabella esistente un campo ID gestito dal database.</li>
<li>E’ disponibile un nuovo tool di geoprocessing (Make Query Layer) che ti consente di utilizzarlo per la creazione di un query layer.</li>
</ul>
<div>
Vedere <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000058000000.htm" target="_blank">What's new for databases</a> per maggiori dettagli.</div>
<div>
</div>
<h4>
<span style="color: red;">Geodatabase</span><div>
</div>
</h4>
<div>
ArcGIS 10.1 contiene numerosi nuovi tool implementati per lavorare con geodatabase 10.1 ed inoltre qualche funzionalità già esistente è stata perfezionata.</div>
<div>
Le nuove funzionalità includono quanto segue:</div>
<div>
</div>
<div>
• E’ disponibile una nuova toolbox – Geodatabase Administration – che contiene alcuni tool presenti precedentemente nella toolbox Database (Upgrade Geodatabase, Upgrade Spatial Reference, Change Privileges, Compress, Migrate Storage e Register With Geodatabase) più i seguenti tool di geodatabase:</div>
<ul>
<li>Create Enterprise Geodatabase: crea un database e un utente administrator del geodatabase in PostgreSQL o SQL Server ed abilita le funzionalità enterprise dei geodatabase, oppure crea un tablespace e un administrator del geodatabase in un database Oracle esistente ed abilita la funzionalità enterprise dei geodatabase. Questo tool esegue la creazione dell’administrator del geodatabase, la creazione del geodatabase e le funzioni di autorizzazione precedentemente ottenute con ArcSDE per SQL Server, Oracle e PostgreSQL Post Installation su Windows. </li>
<li>Enable Enterprise Geodatabase: abilita le funzionalità dei geodatabase in un esistente database DB2, Informix, Oracle, PostgreSQL o SQL Server. Questo tool esegue la creazione di un geodatabase e le funzioni di autorizzazione precedentemente ottenute con ArcSDE per DB2 ed Informix Post Installation su Windows.</li>
<li>Rebuild Indexes: i proprietari dei dati possono usare questo tool per ricostruire gli indici su più feature class. Gli administrator di geodatabase possono usare questo tool per ricostruire indici sulle tabelle di sistema state, state_lineage e mv_tables_modified. Questo sostituisce il tool Rebuild Index.</li>
<li>Analyze Datasets: i proprietari di dati possono usarlo per aggiornare le statistiche di un database per più feature class . Gli administrator di geodatabase possono aggiornare le statistiche del database su tutte le tabelle di sistema di geodatabase. Questo tool sostituisce la finestra di dialogo Analyze aperta dal comando <em><strong>Analyze</strong></em> sul context menu del dataset.</li>
<li>Reconcile Versions: riconcilia e posta le modifiche versionate nell’ordine raccomandato per ottimizzare un’operazione succcessiva di compressione del geodatabase. Questo tool sostituisce il Reconcile Version, che era in grado di riconciliare solo una versione alla volta.</li>
<li>Create Versioned View: i proprietari di dati possono creare viste versionate (prima chiamate multiversioned views) con un nome specificato dall' utente su una feature class versionata. Se esiste già una vista versionata sulla feature class, questa viene eliminata in favore di quella nuova creata.</li>
<li>Create Database View: puoi definire una vista su un database o un geodatabase enterprise su una o più tabelle.</li>
<li>Create Database User: puoi creare utenti in un geodatabase o in un database enterprise. Questo tool può essere utilizzato con Oracle, PostgreSQL o SQL Server. Agli utenti sono garantiti i privilegi minimi per poter creare oggetti database. In SQL Server vengono garantiti privilegi sufficienti per leggere le tabelle di sistema contenenti liste di login e ruoli del database, In Oracle, vengono creati con privilegi sufficienti per leggere la tabella dei ruoli del database.</li>
<li>Create Role: puoi creare il ruolo di un database in un geodatabase o database enterprise ed aggiungere utenti al ruolo. Si può usare questo tool con server Oracle, PostgreSQL o SQL.</li>
</ul>
<div>
• Il nuovo tool di geoprocessing Create Database Connection ti consente di creare connessioni ai geodatabase enterprise o database .</div>
<div>
• La nuova finestra di dialogo <strong><em>Geodatabase Administration</em></strong> permette agli amministratori di geodatabase di visualizzare ed amministrare connessioni, lock dei dati e versioni dell’utente.</div>
<div>
• Gli administrator dei geodatabase sono in grado di bloccare nuove connessioni al geodatabase cambiando una proprietà sulla connessione del database in ArcGIS for Desktop.</div>
<div>
• I proprietari dei dataset possono visualizzare i lock effettuati sui loro dati in un database enterprise.</div>
<div>
• E possibile impostare i propri dataset per memorizzare informazioni su modifiche apportate ai dati e su chi ha inserito ogni registrazione. Ciò è particolarmente utile se hai un sistema distribuito nel quale gli utenti apportano modifiche da diverse postazioni attraverso feature service. Puoi abilitare l’editor tracking dal context menu di tabelle o feature class item (<strong>Enable Editor Tracking</strong>), o ad utilizzando il nuovo tool di geoprocessing Editor Tracking. Poi, se vuoi limitare l’accesso alle feature attraverso un feature service, puoi abilitare il controllo di accesso basato sul proprietario sul feature service quando viene pubblicato.</div>
<div>
• Sono disponibili nuovi tool di geoprocessing per creare e gestire geometric network:</div>
<ul>
<li>Add Edge-Edge Connectivity Rule To Geometric Network</li>
<li>Add Edge-Junction Connectivity Rule To Geometric Network</li>
<li>Create Geometric Network</li>
<li>Remove Connectivity Rule From Geometric Network</li>
<li>Remove Empty Feature Class From Geometric Network</li>
<li>Trace Geometric Network</li>
<li>Set Flow Direction</li>
</ul>
<div>
• E’ disponibile un nuovo tool di geoprocessing (Export Topology Errors) che permette di esportare errori di topologia per le tre feature class, uno per ogni tipo di geometria di errore di topologia.</div>
<div>
• Il nuovo toolset di geoprocessing Attachments contiene i seguenti tool per aiutarti ad eseguire operazioni batch di attachment dei file:</div>
<ul>
<li>Enable Attachments</li>
<li>Add Attachments</li>
<li>Remove Attachments</li>
<li>Disable Attachments</li>
<li>Generate Attachment Match Table</li>
</ul>
<div>
• Si creano automaticamente viste versionate su tutti i dati registrati come versionati in ArcGIS 10.1. Per gli esistenti dati versionati, puoi creare viste versionate adoperando il comando Create Versioned Views in ArcGIS for Desktop o il nuovo tool di geoprocessing Create Versioned Views o uno script di Python.</div>
<div>
• Il nuovo tool di geoprocessing Upgrade Dataset aggiorna dataset mosaic, parcel fabric e network dataset all'ultima release di ArcGIS.</div>
<div>
• Il nuovo tool di geoprocessing Truncate Table può essere utilizzato per cancellare tutte le righe di una tabella.</div>
<div>
• Sono disponibili nuove <a href="http://www.esri.com/apps/products/download/index.cfm?fuseaction=#http://www.esri.com/apps/products/download/index.cfm?fuseaction=/file_geodatabase_api_1.2" target="_blank">API</a> che ti consente di accedere direttamente ai file geodatabase senza usare ArcObjects.</div>
<div>
• I nuovi geodatabase e quelli aggiornati di SQL Server useranno di default il tipo Geometry di SQL Server per le feature class.</div>
<div>
</div>
<div>
I miglioramenti apportati alla funzionalità comprendono:</div>
<div>
</div>
<div>
• Le connessioni ai database vengono fatte dal nodo Database Connection (prima Spatial Database Connection) nella treebox del Catalog. La stessa finestra di dialogo per le connessione è stata modificata:</div>
<ul>
<li>Ti consente di connetterti ai database che non contengono tabelle, funzioni e procedure di geodatabase.</li>
<li>Semplifica le connessioni ai geodatabase.</li>
<li>Una volta che hai fornito username e password connettendoti ad un’istanza di SQL Server o ad un cluster database PostgreSQL, puoi scegliere da una lista a discesa di database disponibili per fare la tua connessione.</li>
</ul>
<div>
• La finestra di dialogo <em><strong>Privileges</strong></em> è stata perfezionata come segue:</div>
<ul>
<li>Puoi vedere esplicitati quali privilegi un utente può utilizzare su un dataset.</li>
<li>Puoi concedere e revocare privilegi su dataset di database o geodatabase.</li>
<li>A seconda del DBMS e dei propri permessi, è possibile vedere una lista di ruoli (o gruppi) ed utenti del database ai quali puoi assegnare privilegi.</li>
<li>Indipendentemente, puoi concedere o revocare privilegi di update, insert e delete su dataset non versionati.</li>
<li>Nuovi oggetti aggiunti al feature dataset ereditano i privilegi concessi allo stesso; non hai più bisogno di ri-concedere privilegi dopo aver aggiunto il nuovo oggetto al feature dataset.</li>
</ul>
<div>
• L’interfaccia del Version Manager (spostato nella nuova finestra di dialogo <strong><em>Geodatabase Administrator</em></strong>) è stata migliorata per consentire più informazioni e funzionalità.</div>
<ul>
<li>Una vista ad albero per mostrare come le versioni sono relazionate.</li>
<li>Una lista per gli administrator di geodatabase per mostrare l’ordine consigliato per riconciliare versioni di geodatabase.</li>
<li>La possibilità del proprietario della versione di cambiare i privilegi su più versioni alla volta.</li>
<li>La possibilità di cancellare una versione e tutte le sue versioni-figlie.</li>
</ul>
<div>
• Il tool Register with Geodatabase in ArcGIS per Desktop è stato modificato per registrare completamente le feature class del database; non devi più registrare con ArcSDE e geodatabase separatamente.</div>
<div>
• Ora puoi controllare il livello di informazioni scritte nel log delle attività della replica. Imposta il livello di log attraverso la finestra di dialogo <strong><em>Replication Manager</em></strong>.</div>
<div>
• Puoi apportare modifiche alle topologie versionate senza dover deversionare il feature dataset nel quale sono memorizzate.</div>
<div>
• Puoi vedere i proprietari dei domini in un geodatabase enterprise guardando il tab <strong>Domains</strong> della finestra di dialogo <strong><em>Database Properties</em></strong>. E’ stata aggiunta una nuova colonna nell’interfaccia denominata Domain Owner.</div>
<div>
• Puoi rinominare gli attributi dei domini.</div>
<div>
• Il nuovo tool di geoprocessing Sort Coded Value Domain ti permette di ordinare il codice o la descrizione di domini per domini con valore a codice.</div>
<div>
• Puoi rinominare i campi nelle tabelle e nelle feature class.</div>
<div>
</div>
<div>
Le modifiche apportate ai setup comprendono:</div>
<div>
</div>
<div>
• Per connettersi direttamente ad un database o ad un geodatabase enterprise devi installare il client DBMS sulla macchina client AcGIS. Puoi scaricare i file client DBMS dal portale Customer Care di Esri.</div>
<div>
• L’applicazione server ArcSDE e i comandi di amministrazione sono forniti come download separati da ArcGIS for Server. Nota bene che l’applicazione server ArcSDE e i comandi di amministrazione sono solo supportati su sistemi operativi a 64 bit.</div>
<div>
• Non c’è bisogno di nessuna installazione separata per geodatabase in DB2 su z/OS dal momento che non usa connessioni al server di applicazione. I file necessari alla creazione di un geodabase in DB2 su z/OS si trovano nella cartella DatabaseSupport dei client ArcGIS.</div>
<div>
</div>
<div>
Per ulteriori informazioni, consultare <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000031000000.htm" target="_blank">What’s new for geodatabases</a>.</div>
<div>
</div>
<h4>
<span style="color: red;">ASCII o tabelle da file di testo</span></h4>
<div>
</div>
<div>
Il processo per accedere ai dati in file con testo delimitato e per la loro gestione come input per un layer è stato semplificato in ArcGIS 10.1. Piuttosto che utilizzare il Microsoft OLE DB provider per Open Database Communication (ODBC) driver e il Microsoft ODBC Text Driver per i file di testo per accedere ai dati tabulati in file di testo, ArcGIS legge questi file direttamente. Questo significa che i file schema.ini non sono più richiesti per visualizzare le informazioni da un file di testo. Comunque, se un file schema.ini è presente, ArcGIS userà le impostazioni nel file per visualizzare i dati.</div>
<div>
Inoltre, ArcGIS riconosce le informazioni sulle coordinate nel file ASCII o di testo come campi numerici, che possono essere usati o per visualizzare le informazioni come layer o come input per i task come ad esempio il geocoding.</div>
<div>
Ci sono anche meno restrizioni sui caratteri che possono venire utilizzati nei nomi di campi dei file ASCII o testo.</div>
<div>
Vedere <a href="http://resources.arcgis.com/en/help/main/10.1/005s/005s00000010000000.htm" target="_blank">Adding an ASCII or text file table</a> per ulteriori informazioni. </div>
<div>
</div>
<h4>
<span style="color: red;">Editing</span></h4>
<div>
</div>
<div>
In ArcGIS 10.1, l’ambiente di editing di ArcMap contiene rilevanti miglioramenti per lavorare coi modelli feature, l’editing sulle feature coincidenti, topologia ed editing di particelle, così come altri miglioramenti generali.</div>
<div>
Quando si creano feature, lavorare con i modelli feature è più facile e ti fornisce un migliore feedback. Inoltre ci sono nuovi tool disponibili per creare feature di tipo poligonale.</div>
<ul>
<li>Si creano modelli di feature basandosi su un layer per layer invece che per un workspace. Se inizi l’editing e non sono presenti modelli di feature per un particolare layer essi verranno creati.</li>
<li>Quando i modelli di feature per layer editabili non sono stati visualizzati, appare un messaggio in alto alla finestra <strong><em>Create Features</em></strong>. Cliccandoci si visualizza una lista dei modelli di feature nascosti ed si ottiene una spiegazione del motivo per cui non sono stati mostrati.</li>
<li>Il nuovo tool di creazione Auto-Complete Freehand appende poligoni a quelli esistenti creando lo shape di un nuovo poligono disegnando una linea che segue il movimento del puntatore.</li>
</ul>
<div>
E’ più facile lavorare con la topologia e le feature condivise, anche attraverso la topologia della mappa. Ci sono anche miglioramenti per selezionare e modificare gli elementi topologicamente:</div>
<ul>
<li>La nuova finestra di dialogo <strong><em>Select Topology</em></strong> integra l’uso della lista a discesa nella toolbar <strong><em>Topology</em></strong> per scegliere la topologia ed aprire una finestra di dialogo diversa per creare la topologia di una mappa. Adesso puoi eseguirlo da una singola finestra di dialogo.</li>
<li>La topologia della mappa adesso utilizza le informazioni del layer e riflette le sue proprietà, inclusi nome e visibilità.</li>
<li>Il tool Reshape Edge ti consente di selezionare e rimodellare contorni multipli in una volta. Usa il nuovo tool Topology Edit Trace per selezionare edge multipli connessi.</li>
<li>La finestra <em><strong>Shared Features</strong></em> è dockable ed è stata migliorata.</li>
<li>Le toolbar <strong><em>Topology</em></strong> e <strong><em>Advanced Editing</em></strong> sono state riprogettate. </li>
<li>Sono stati semplificati lo splitting e il moving della topologia dell’edge.</li>
<li>Il nuovo tool Generalize Edge viene usato per semplificare la topologia dell’edge.</li>
<li>E' possibile aggiungere una regola o una feature class o rimuoverla da un geodatabase con topologia versionata senza doverla deversionare.</li>
</ul>
<div>
ArcGIS 10.1 ha una serie di nuovi tool che sono stati progettati per aiutarti nel rendere i tuoi dati contigui. Alcuni di questi tool lavorano con feature mentre altri richiedono una topologia. Tali tool includono: Align To Shape, Replace Geometry e Align Edge.</div>
<div>
ArcGIS 10.1 include la possibilità di registrare informazioni circa chi ha apportati i cambi ai dataset e quando le modifiche sono state eseguite. Attraverso l’Editor Tracking, il nome dell’utente dell’editor e un time stamp sono memorizzati nei campi degli attributi direttamente nel dataset. L’editor tracking può aiutarti a mantenere il controllo, elevare gli standard del controllo qualità e creare un log dei cambi effettuati nei dati.</div>
<div>
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000002v000000.htm" target="_blank">What's new for editing in ArcGIS 10.1</a> per ulteriori informazioni.</div>
<div>
</div>
<h4>
<span style="color: red;">Editing di particelle</span></h4>
In ArcGIS 10.1, si sono apportati miglioramenti significativi alla gestione ed all’editing del dataset parcel fabric.<br />
<ul>
<li>Si può accedere alle feature class ed alle tabelle delle parcel fabric espandendo il dataset parcel fabric in ArcCatalog o nella Window <strong><em>Catalog</em></strong>. Ora puoi aggiungere sublayer di parcel fabric in ArcMap senza dover aggiungere il layer parcel fabric.</li>
<li>I dataset parcel fabric o le selezioni di dataset parcel fabric possono essere copiate o accodate utilizzando il nuovo tool di geoprocessing Append Parcel Fabric e Copy Parcel Fabric.</li>
<li>Si possono sistemare le traverse delle particelle per eliminare le chiusure usando il metodo Compass, il metodo Transit o il metodo Crandall.</li>
<li>Si è migliorato ulteriormente le traverse delle particelle in modo da consentire di specificare la coordinata iniziale e finale per la traversa della particella.</li>
<li>Ora si possono creare le particelle <a href="http://resources.arcgis.com/en/help/main/10.1/index.html#//00wp0000001v000000" target="_blank">remainder</a> in ArcGIS 10.1 da particelle multiple sovrapposte invece che da singole sovrapposte.</li>
<li>Il joining delle particelle è stato migliorato per consentire l’integrazione cartografica di nuove particelle anche quando non confinano.</li>
<li>Inoltre, il joining delle particelle è stato migliorato con il tool trace-link, che puoi utilizzare per individuare join che si agganciano automaticamente lungo il confine tracciato.</li>
<li>Si può muovere o trasformare una selezione di particelle utilizzando il nuovo tool Transform Parcels.</li>
<li>Le repliche adesso sono supportate per i dataset parcel fabric.</li>
<li>Gli attributi delle feature dei dataset parcel fabric possono essere modificati nella finestra <strong><em>Attributes</em></strong>.</li>
<li>Il nuovo tool Annotate Parcel Courses può essere utilizzato per annotare e rimuovere annotation duplicate da una selezione di particelle. Questo tool è utile per gestire annotation duplicate su linee di confine dei dataset parcel fabric.</li>
</ul>
<div>
In ArcGIS 10.1 i dataset parcel fabric sono supportati dalle repliche.</div>
<div>
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000002v000000.htm#ESRI_SECTION1_B6203B82CEDB4B2BBF09B38A30F376BB" target="_blank">What’s new for editing in ArcGIS 10.1</a> per altre informazioni.</div>
<br />
<h4>
<span style="color: red;">Dati raster</span></h4>
ArcGIS 10.1 comprende molte nuove opzioni, tool e funzioni ed offre supporto per ulteriori formati di raster. Segue un riassunto delle nuove funzionalità per i dati raster:<br />
<ul>
<li>In generale, ci sono stati significativi progressi nella visualizzazione, nel miglioramento e nel processo di vari tipi di dati raster ed image in ArcGIS.</li>
<li>Si sono aggiunti ulteriori 15 formati nella lettura dei dati raster.</li>
<li>Il prodotto Raster appare come un nuovo tipo di dato ed è stato progettato per aggiungere immagini da un sensore alla mappa più semplicemente.</li>
<li>La finestra <strong><em>Image Analysis</em></strong> fornisce tool di misurazione, una finestra interattiva per lo stretch ed un tool per l’editor della funzione.</li>
<li>Nuove impostazioni di rendering predefiniti sono disponibili per il rendering dei raster ed i predefiniti sono stati migliorati.</li>
<li>Nuovi tool di geoprocessing si sono introdotti e sono stati migliorati alcuni tool esistenti.</li>
<li>E’ disponibile un nuovo supporto per aggiungere direttamente e rasterizzare i dati LAS, dataset terrain o dataset LAS in dataset mosaic.</li>
<li>Funzioni batch di editing sono disponibili per editare funzioni per raster multipli.</li>
<li>Ci sono nuove e migliorate funzionalità in ArcGIS for Server.</li>
</ul>
<div>
Per maggiori informazioni, vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000032000000.htm" target="_blank">What's new for rasters in ArcGIS 10.1</a>.</div>
<div>
</div>
<h4>
<span style="color: red;">Metadati</span></h4>
<div>
</div>
<div>
Le seguenti nuove e migliorate funzionalità sono disponibili per i metadati in ArcGIS 10.1.</div>
<div>
• La validazione è stata estesa per includere più stili di metadati.</div>
<div>
• Si sono apportati miglioramenti alla tabella dei contenuti dell’editor dei metadati per aiutarti a vedere se mancano delle informazioni o se hai tipi di informazioni sbagliati per il tuo stile di metadati.</div>
<div>
• Una pagina dei contatti del manager è stata aggiunta per consentirti di memorizzare i riferimenti di questo contatto che può essere caricato nei tuoi metadati.</div>
<div>
• E’ fornito un nuovo traduttore ArcGIS per l’ISO 19139.</div>
<div>
Per ulteriori informazioni vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000030000000.htm" target="_blank">What's new for metadata in ArcGIS 10.1</a>.<br />
</div>
<h3>
<span style="color: blue;">GEOPROCESSING ED ANALISI</span></h3>
<br />
<div>
ArcGIS 10.1 include i geoprocessing package, numerosi nuovi tool di geoprocessing ed alcune modifiche alla modalità di utilizzo del geoprocessing. Le seguenti sezioni forniscono un riassunto delle modifiche e delle nuove funzionalità. Per ulteriori informazioni, vedi “What’s new in geoprocessing” nell’help e, per iniziare, vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000002s000000.htm" target="_blank">What's new for geoprocessing in ArcGIS 10.1</a>.<br />
</div>
Puoi creare package di geoprocessing per condividere i tuoi geoprocessing task. Un package è formato da task ed ogni task contiene un tool, i dati usati dal tool e le impostazioni d’ambiente utilizzate dal tool.<br />
<div>
E’ cambiato il modo di pubblicare i servizi di geoprocessing. Nel 10.1, pubblichi i risultati delle analisi direttamente dalla finestra <strong><em>Results</em></strong>.<br />
</div>
<h4>
<span style="color: red;">Python ed ArcPy</span></h4>
<br />
<div>
In ArcGIS 10.1, è possibile programmare i button e i tool usando Python add-in. Le toolbox di Python sono un nuovo tipo di toolbox che è possibile creare con Python.<br />
</div>
<h4>
<span style="color: red;">Tools</span></h4>
<div>
<br />
Ci sono numerosi nuovi tool disponibili in ArcGIS 10.1. Vedi la sezione “New and improved tools” sotto “Geoprocessing and Analysis” per visionarne l’elenco.</div>
<br />
<h3>
<span style="color: blue;">SERVIZI</span></h3>
<br />
<div>
ArcGIS for Server è stato riprogettato in 10.1 per lavorare in architetture a 64 bit ed utilizzare un design più adeguato ai sistemi cloud ed ai servizi web. Le seguenti sezioni forniscono alcuni dettagli sulle nuove funzionalità in ArcGIS for Server. Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000036000000.htm" target="_blank">What's new in ArcGIS 10.1 for Server</a> per una lista più dettagliata dei miglioramenti.<br />
</div>
<h4>
<span style="color: red;">Architettura</span></h4>
<div>
<br />
In 10.1, si sono apportate le seguenti modifiche all’architettura ArcGIS for Server:</div>
<ul>
<li>ArcGIS for Server funziona esclusivamente come applicazione nativa a 64 bit.</li>
<li>SOM e SOC sono state sostituite con un solo componente, il server GIS.</li>
<li>Le connessioni locali di ArcGIS for Server (DCOM) non sono più supportate. Tutte le comunicazioni con i servizi GIS passano attraverso HTTP usando SOAP o REST.</li>
<li>ArcGIS for Server può ospitare servizi preconfezionati e non richiede l’installazione di un web server. Eventualmente puoi collegarlo al tuo web server usando un nuovo componente chiamato Web Adapter.</li>
<li>Le nuove API ArcGIS Server Administrator basate su REST ti consentono di amministrare il tuo sito ArcGIS Server tramite script. Con queste API puoi automatizzare task come creare un sito, aggiungere macchine, pubblicare servizi, interrogare i log, far partire e fermare servizi.</li>
</ul>
<br />
<h4>
<span style="color: red;">ArcGIS Server su Amazon Web Services</span></h4>
<br />
Amazon Machine Images (AMI) che si possono utilizzare per distribuire ArcGIS for Server su Amazon Elastic Cloud (EC2) ora sono disponibili con i seguenti sistemi operativi e DBMS: per la piattaforma Linux in aggiunta a quella di Windows. La nuova architettura ArcGIS for Server consente di supportare meglio la creazione di cache e geoprocessing su Amazon EC2.<br />
<ul>
<li>ArcGIS Server su Ubuntu Linux con PostgreSQL</li>
<li>ArcGIS Server su Windows con SQL Server Standard</li>
<li>ArcGIS Server su Windows con SQL Server Express</li>
</ul>
C’è anche una nuova applicazione - ArcGIS Server Cloud Builder su Amazon Web Services - per distribuire il tuo ArcGIS Server sul sito Amazon Web Services, creare template, eseguire backup del proprio sito o cancellare siti.<br />
<br />
<h4>
<span style="color: red;">Pubblicazione</span></h4>
<div>
<br />
E' possibile pubblicare servizi direttamente da ArcGIS for Desktop ed ora si ha l’opzione di copiare i dati relativi al server al momento della pubblicazione. Ciò è particolarmente utile per installazioni distribuite o distribuzioni cloud dove si potrebbe non avere i permessi per accedere al server.</div>
<div>
Un nuovo tipo di file di definizione servizio (.sd) aiuta in questo senso. Contiene la completa definizione di un servizio GIS. Un file SD può essere salvato e copiato tra macchine.</div>
<div>
Tutti i servizi di mappa ora necessitano di utilizzare l’engine ottimizzato di visualizzazione, introdotto come nuova opzione dalla 9.3.1.<br />
</div>
<h4>
<span style="color: red;">Web ADF</span></h4>
<div>
<br />
ArcGIS 10.1 for Server è l’ultima release che supporta ArcGIS Server Web ADF per Microsoft .NET e Java. La conseguenza è che il Web ADF Application Manager è stato spostata in una installazione separata. Le nuove applicazioni web andrebbero scritte come applicazioni JavaScript, Flex o Silverlight.</div>
<div>
Inoltre, le connessioni locali in ArcGIS for Server (DCOM) alle applicazioni web ADF non sono più supportate e nemmeno le applicazioni web ADF che usano servizi non pooled; eccezion fatta per le connessioni a servizi pre 10.1.<br />
</div>
<h3>
<span style="color: blue;">GIS mobile</span></h3>
<br />
Le applicazioni ArcGIS smartphone ed i pacchetti per lo sviluppo di applicazioni (SDK) sono rilasciate più frequentemente rispetto ad ArcGIS, inoltre tutti i prodotti mobile hanno nuove funzionalità disponibili da ArcGIS 10.1:<br />
<ul>
<li>ArcGIS for Android</li>
<li>ArcGIS for iOS</li>
<li>ArcGIS for Windows Phone</li>
<li>ArcGIS for Windows Mobile</li>
<li>ArcPad</li>
</ul>
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000057000000.htm" target="_blank">What's new for Mobile GIS</a> per funzionalità e versioni specifiche.<br />
<br />
<h3>
<span style="color: blue;">Estensioni ArcGIS</span> </h3>
<div>
<br />
Segue un riassunto delle nuove funzionalità e modifiche delle estensioni di ArcGIS:<br />
</div>
<h4>
<span style="color: red;">Estensione per ArcGIS 3D Analyst</span></h4>
<div>
<br />
In ArcGIS 10.1, l’estensione ArcGIS 3D Analyst è stata estesa con l’integrazione online del 3D, che comprende un blog attivo ed una gallery di template dalla quale puoi scaricare dati per esercitarsi ad utilizzare dati e scenari 3D.</div>
<div>
Inoltre, in 3D Analyst è stato migliorato il supporto per dati di city e campus 3D per città e modelli di campus virtuali. Anche l’uso dell’editing è stato migliorato, così come la visualizzazione per la gestione dell’ambiente urbano ed il supporto per la visualizzazione di grandi dataset.</div>
<div>
In aggiunta, è stato migliorato il supporto per lidar in 3D Analyst, specialmente nello sviluppo dei dataset LAS. Ora ArcGIS 10.1 legge i file LAS nativamente, perciò fornendo accesso immediato ai dati lidar senza la necessità di conversioni o importazione di dati. Molti nuovi metodi di ottimizzazione sono disponibili per gestire, visualizzare ed analizzare questi file LAS.</div>
<div>
Ci sono anche numerosi nuovi tool di geoprocessing per lavorare con dati 3D. Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000033000000.htm" target="_blank">What's new in ArcGIS 3D Analyst 10.1</a> per ulteriori informazioni.<br />
</div>
<h4>
<span style="color: red;">Estensione ArcGIS Data Interoperability</span></h4>
<div>
<br />
In ArcGIS 10.1, l’estensione Data Interoperability è stata aggiornata per eseguire la nuova piattaforma FME 2012 spatial data transformation da Safe Software. Oltre alle nuove trasformazioni ed al supporto migliorato per lidar, l’estensione adesso è installata con i seguenti setup indipendenti:</div>
<ul>
<li>ArcGIS Data Interoperability extension for Desktop </li>
<li>ArcGIS Data Interoperability extension for Server</li>
</ul>
Puoi installare entrambi i setup sulla stessa macchina a 64-bit ed eseguirli contemporaneamente.<br />
<div>
ArcGIS Data Interoperability extension for Server richiede una propria licenza e non è intercambiabile con una licenza desktop.</div>
<div>
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000005p000000.htm" target="_blank">What’s new in the Data Interoperability extension</a> per ulteriori informazioni.<br />
</div>
<h4>
<span style="color: red;">Estensione ArcGIS Geostatistical Analyst</span></h4>
<br />
Ci sono due nuovi metodi di interpolazione disponibili nell’estensione ArcGIS Geostatistical Analyst: <br />
<ul>
<li>Areal interpolation, che estende la teoria di kriging per dati mediati o aggregati su poligoni</li>
<li>Empirical Bayesian kriging, che usa simulazioni ripetute ad account per l’errore introdotto stimando il semivariogramma.</li>
</ul>
E’ disponibile una nuova trasformazione normale di punteggio: il metodo multiplicative skewing approximation per la trasformazione normale di punteggio. Questa è ora la trasformazione di default per il kriging semplice.<br />
<div>
Il kriging semplice è ora il metodo di kriging predefinito per Geostatistical Analyst.</div>
<div>
I tool di Geostatistical Analyst adesso supportano l’ambiente di mask.</div>
<div>
Per ulteriori informazioni, vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000003n000000.htm" target="_blank">What's new in ArcGIS Geostatistical Analyst 10.1</a>.<br />
</div>
<h4>
<span style="color: red;">Estensione ArcGIS Network Analyst</span></h4>
<div>
<br />
Ci sono 5 nuovi tool di geoprocessing per l’estensione ArcGIS Network Analyst in ArcGIS 10.1:</div>
<ul>
<li>Generate Service Areas</li>
<li>Solve Vehicle Routing Problem</li>
<li>Update Traffic Data</li>
<li>Update Traffic Incidents</li>
<li>Copy Traversed Features</li>
</ul>
C’è un nuovo modulo Network Analyst in ArcPy site package; inoltre è disponibile il supporto agli script Python per campi script dei valutatori.<br />
<div>
Una nuova funzionalità per Network Analyst include la possibilità di usare la gerarchia di una network per risolvere aree di servizio; è stato esteso il supporto dei dati di traffico storico per tutti i solver; il supporto per il traffico corrente per tutti i solver; è stato esteso il modello di restrizioni che consente, non solo di proibire elementi di network interamente, ma anche singolarmente; più diverse nuove funzionalità per l’estensione ArcGIS for Server Network.</div>
<div>
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000020000000.htm" target="_blank">What's new in ArcGIS Network Analyst 10.1</a> per ulteriori informazioni.<br />
</div>
<h4>
<span style="color: red;">Estensione ArcGIS Schematics</span></h4>
<div>
<br />
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000056000000.htm" target="_blank">What's new in ArcGIS Schematics 10.1</a> per ulteriori informazioni.</div>
<br />
<h4>
<span style="color: red;">Estensione ArcGIS Spatial Analyst</span></h4>
<div>
<br />
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000028000000.htm" target="_blank">What's new in ArcGIS Spatial Analyst 10.1</a> per ulteriori informazioni.</div>
<br />
<h4>
<span style="color: red;">Estensione ArcGIS Tracking Analyst</span></h4>
<br />
<div>
Ci sono due nuove finestre dockable disponibili per l’estensione ArcGIS Tracking Analyst nella release ArcGIS 10.1:</div>
<ul>
<li>Track Manager ti consente di visualizzare ed interagire con le tracce e le tracking feature contenute nella mappa.</li>
<li>Tracking Services Monitor ti consente di visualizzare e monitorare lo stato dei tuoi servizi real time di tracking.</li>
</ul>
Inoltre, ci sono due nuovi tool di geoprocessing disponibili per l’estensione ArcGIS Tracking Analyst nella release ArcGIS 10.1:<br />
<ul>
<li>Track Intervals To Feature</li>
<li>Track Intervals To Line</li>
</ul>
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000021000000.htm" target="_blank">What's new in ArcGIS Tracking Analyst 10.1</a> per ulteriori informazioni.<br />
<br />
<h4>
<span style="color: red;">Maplex</span></h4>
<div>
<br />
Le funzionalità dell’estensione ArcGIS Maplex sono state spostate nel core del prodotto ArcGIS for Desktop ed è definito come Maplex Label Engine.<br />
</div>
<h3>
<span style="color: blue;">Soluzioni per l’Industria</span></h3>
<h4>
<span style="color: red;">Difesa ed Intelligence</span></h4>
<br />
<div>
In ArcGIS 10.1, i dati nei layer rappresentanti elementi militari distribuiti attraverso ArcGIS.com sono rappresentati usando valori unici basati su due campi. Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w0000002q000000.htm" target="_blank">What's new for defense and intelligence in ArcGIS 10.1</a> per ulteriori informazioni.<br />
</div>
<h4>
<span style="color: red;">Geocoding</span></h4>
<br />
<div>
Le seguenti nuove funzionalità sono disponibili per il geocoding in ArcGIS 10.1:</div>
<ul>
<li>Puoi creare e condividere Package Locator che sono file compressi contenenti un locator o un locator composito con i locator che lo compongono.</li>
<li>Puoi pubblicare servizi di geocode direttamente da un locator o da un locator composito in ArcGIS for Desktop.</li>
<li>Una nuova finestra di dialogo <strong><em>Address Locator Properties</em></strong> è disponibile che ti consente di modificare le impostazioni di un locator.</li>
<li>La toolbar <strong><em>Geocoding</em></strong> e la finestra di dialogo <strong><em>Find</em></strong> contengono una nuova opzione - <strong>Use Map Extent</strong> – che ti consente di cercare località che sono relative soltanto all’estensione della mappa corrente.</li>
<li>Ci sono due nuovi stili di address locator che sono stati aggiunti: US Address-Street Name e US Address-City State.</li>
<li>Ci sono due nuovi tool di geoprocessing nella tool geocoding: Consolidate Locator e Package Locator.</li>
</ul>
Vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000034000000.htm" target="_blank">What's new for geocoding</a> per ulteriori informazioni.<br />
<br />
<h3>
<span style="color: blue;">SVILUPPO</span></h3>
<br />
<div>
Sono disponibili dei nuovi pacchetti per sviluppo (SDK) di applicazioni: ArcGIS Runtime SDK per Windows e Linux.</div>
<div>
Sono stati apportati alcuni miglioramenti negli SDK disponibili per le applicazioni mobile.</div>
<div>
Ci sono stati alcuni cambiamenti negli ArcObject (.NET) per quanto riguarda gli enumeratori e l’architettura, nuove feature come la possibilità di rinnovare o aggiornare l’SDK silenziosamente ed un modello di distribuzione per le server object extension. Sono disponibili nuovi esempi e si sono migliorate le librerie in tutto il software.</div>
<div>
Per ulteriori informazioni, vedi <a href="http://resources.arcgis.com/en/help/main/10.1/016w/016w00000059000000.htm" target="_blank">what’s new for developers</a>.<br />
<br />
</div>
<h3>
<span style="color: blue;">AMMINISTRAZIONE LICENZE ARCGIS</span></h3>
<br />
<div>
Nella versione 10.1, rinnovare o aggiornare la licenza è stato reso più semplice ed i miglioramenti sono stati eseguiti nel License Server Administrator.<br />
</div>
<h4>
<span style="color: red;">Aggiornamento o rinnovo automatico delle licenze</span></h4>
<br />
<div>
ArcGIS for Desktop, ArcGIS Engine e License Manager adesso ti consentono di aggiornare vecchie versioni di licenze o rinnovare licenze scadute sulla tua macchina senza dover riautorizzare il tuo software. Una volta che è installato ArcGIS for Desktop, sei portato ad aggiornare o rinnovare le licenze quando l’ArcGIS Administrator è eseguito. Per ArcGIS Engine le licenze possono essere rinnovate lanciando l’ArcGIS Administrator, aprendo la cartella Support Operations e poi cliccando Renew o Upgrade, che lancia l'Authorization Wizard. L'Authorization Wizard poi controlla Esri Customer Service per rinnovare o aggiornare le licenze attraverso questo processo.</div>
<br />
<h4>
<span style="color: red;">Migliore visualizzazione delle licenze in License Server Administrator</span></h4>
<br />
<div>
License Server Administrator ora visualizza le licenze trasferite e in check out oltre alle licenze borrow nella finestra <strong><em>Availability</em></strong>.</div>
<br />
<h4>
<span style="color: red;">Deautorizzazione selettiva</span></h4>
<br />
<div>
Per ArcGIS for Desktop ed ArcGIS Engine Concurrent Use e Single Use, puoi ora scegliere quale licenza deautorizzare invece di deautorizzare tutte le licenze per default.</div>
<br />
<h3>
<span style="color: blue;">DOCUMENTAZIONE</span></h3>
<br />
<div>
In ArcGIS 10.1, se soffermi il cursore su un controllo in una toolbar o in una voce di menu, vedi una descrizione più lunga come ToolTip piuttosto che una sola riga di ToolTip, come era precedentemente. Alcuni di questi ToolTip contengono un link all’help installato di ArcGIS for Desktop così che tu possa accedere a maggiori informazioni. Questi ToolTip sostituiscono gli help di pop-up dipendenti dal contesto, a cui prima si accedeva attraverso il tool di help <strong><em>What’s This</em></strong> nella toolbar <strong><em>Standard</em></strong>. Questo è stato rimosso nella 10.1 e l’aiuto dipendente dal contesto è stato eliminato. Gli sviluppatori ArcObjects possono specificare questi nuovi stili di ToolTip per i controlli che creano ed includere link nel ToolTip o a file CHM o a pagine web.</div>
<div>
I pop-up dell’help dipendenti dal contesto nelle finestre di dialogo sono stati eliminati in 10.1 ed il punto interrogativo (?) nell’angolo in alto a destra della finestra di dialogo è stato rimosso. Invece, link agli argomenti dell’Help del Desktop installato sono stati aggiunti in molte finestre di dialogo. La rimozione dei pop-up dell’help dipendente dal contesto che erano basati sull’obsoleto formato Microsoft WinHelp (HLP) migliora la compatibilità di ArcGIS con Window 7.</div>
Inoltre, l’<a href="http://links.esri.com/arcgis-resourcecenter/home" target="_blank">ArcGIS Resource Center</a> è stato riorganizzato a seconda della funzionalità per rendere più facile la ricerca di tutte le risorse online per un particolare aspetto di ArcGIS.<br />
<div>
</div>
<br />
<div>
</div>
<div>
</div>
Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.25583345.588721 9.253365500000001 45.591499000000006 9.2583005tag:blogger.com,1999:blog-8323071861123024882.post-4802078202391154802012-07-31T20:04:00.000+02:002012-09-05T22:01:58.977+02:00ArcGIS Server: FDGB vs EGDBQuando si distribuisce un sito di ArcGIS Server, è necessario decidere dove memorizzare i dati utilizzati dai servizi GIS. Vi sarete chiesti: ma è meglio utilizzare i geodatabase ArcSDE (EGDB) o i file geodatase (FGDB)? Illustriamo ora alcuni scenari che aiutano nella scelta migliore.<br />
<br />
<h4>
Quando utilizzare geodabase ArcSDE rispetto a file geodatabase</h4>
<br />
In genere è consigliabile utilizzare un geodatabase ArcSDE enterprise per gestire i dati per i servizi. <br />
ArcSDE offre supporto per alta disponibilità, backup e ripristino, concorrenza, scalabilità e una tendenza a fornire throughput superiori. <br />
Tuttavia, questa scelta è consigliata col presupposto che l'organizzazione disponga di un amministratore di database (DBA) per ottimizzare, eseguire tuning e mantenere il geodatabase ArcSDE enterprise in condizioni di massima efficienza.<br />
Se l'organizzazione non dispone di un DBA nel personale a sua disposizione e i dati pubblicati sono relativamente statici, l’utilizzo di un file geodatabase può essere una buona alternativa. <br />
I file geodatabase generalmente forniscono ottime prestazioni senza la necessità di configurazioni aggiuntive o di tuning. A seconda delle caratteristiche dei dati GIS, in alcuni casi potrebbero essere necessarie ulteriori ottimizzazioni e tuning di un geodatabase ArcSDE enterprise per superare le prestazioni di un file geodatabase.<br />
In flussi di lavoro di caching di mappe e di globi dove vengono effettuate molte chiamate di sola lettura ai dati in rapida successione, l’accesso ai file geodatabase attraverso percorsi locali spesso è migliore rispetto ai geodatabase ArcSDE.<br />
Prima di optare per l’utilizzo di un file geodatabase, occorre ricordarsi che alcune funzionalità del geodatabase ArcSDE, quali versioning, repliche geodatabase e archiving, non sono disponibili nei file geodatabase. Inoltre, le funzionalità standard dei DBMS come logging, backup e ripristino e configurazione di failover non sono disponibili nei file geodatabase.<br />
<h4>
<br />Considerazioni per i file geodatabase</h4>
<br />
Quando si utilizzano i file geodatabase per la memorizzazione dei dati, è necessario posizionare una copia identica del file geodatabase su ogni macchina server GIS. Ad esempio, in un sito di ArcGIS Server con tre server GIS, ogni server GIS deve accedere alla propria copia del file geodatabase. I server GIS non dovrebbero accedere allo stesso file geodatabase attraverso la rete.<br />
Questa configurazione riduce al minimo il traffico di rete tra le diverse componenti di ArcGIS Server e riduce i conflitti I/O quando si accede al file geodatabase. Fattori che influenzano potenziali conflitti di I/O su disco per un file geodatabase condiviso includono il numero di layer nel servizio di mappa, i tipi di dati nel file geodatabase e il dispositivo di memorizzazione dei file.<br />
I file geodatabase sono destinati per l'utilizzo in sola lettura con ArcGIS Server. <br />
Per questo motivo, in scenari in cui il file geodatabase è una pubblicazione di geodatabase (in flussi di lavoro di replica one-way), la sincronizzazione di repliche deve verificarsi durante i periodi di inattività del servizio di mappa o rilasciando il file geodatabase dall’utilizzo da parte del servizio di mappa. Il rilascio del geodatabase può essere effettuato arrestando il servizio o, per i siti su più computer, rimuovendo temporaneamente le macchine server GIS dal sito, quindi ricollegarle dopo che il file geodatabase è stato aggiornato.<br />
Una replica one-way è un'ottima soluzione per pubblicare ad esempio feature class da un sistema di coordinate ad un altro in fase di pubblicazione (ad esempio dal proprio sistema proiettato a web mercator adatto per la pubblicazione). Per maggiori dettagli <a href="http://support.esri.com/en/knowledgebase/techarticles/detail/34129">http://support.esri.com/en/knowledgebase/techarticles/detail/34129</a><br />
<a href="http://support.esri.com/en/knowledgebase/techarticles/detail/34143">http://support.esri.com/en/knowledgebase/techarticles/detail/34143</a><br />
<br />
L’ArcGIS Server non può disabilitare il blocco dello schema sui file geodatabase.<br />
<br />
<h4>
File geodatabase e caching di mappe</h4>
<br />
I file geodatabase funzionano bene per scenari di caching di mappa. Ponendo un file geodatabase identico su ogni macchina a lavorare sulla cache, è possibile eliminare molte chiamate al database ArcSDE che avrebbe bisogno di attraversare la rete. Questo può alleggerire il carico sul database e velocizzare la produzione di cache. È possibile utilizzare repliche one-way da ArcSDE per creare questi file geodatabase e, come già detto, possiamo anche replicare nella proiezione della mappa che verrà memorizzata nella cache. L’esempio classico è memorizzare la cache di una mappa web nella proiezione WGS 1984 Web Mercator (sfera ausiliaria) utilizzata da ArcGIS Online, Bing Maps e Google Maps. Questa non è solitamente una proiezione consigliata per memorizzare i propri dati in ArcSDE, ma è una buona proiezione per creare cache di una mappa web da un file geodatabase.Ing. Domenico Ciavarellahttp://www.blogger.com/profile/11116200904149667988noreply@blogger.com0Via Luciano Manara, 48, 20900 Monza MB, Italia45.59011 9.25583345.588721 9.253365500000001 45.591499000000006 9.2583005