Generare "ad hoc" un menù multilivello: struttura dati e conversione da XML a HTML utilizzando XSLT

Ho utilizzato questa tecnica per generare dinamicamente un accordion menù multilivello ...
Consideramo il seguente diagramma ad albero, rappresentazione della struttura di un possibile menù di navigazione:
- Root (nodeID=1, parentID=0)
- Item 1 (nodeID=2, parentID=1)
  - item 1.1 (nodeID=3, parentID=2)
  - item 1.2 (nodeID=4, parentID=2)
     - item 1.2.1 (nodeID=5, parentID=4)
  - item 1.3 (nodeID=6, parentID=2)
- Item 2 (nodeID=7, parentID=1)
La seguente struttura può essere memorizzata nella seguente tabella di un database: MenuTable(nodeID,parentID,title).
A partire dalla tabella MenùTable è possibile generare facilmente la rappresentazione XML del grafo ad albero utilizzando il seguente codice:
Dim sqlString As String = "SELECT NodeID, ParentID, title FROM MenuTable ORDER BY NodeID"
        Dim cmd As SqlCommand = New SqlCommand(sqlString)
        Dim conn As SqlConnection
        conn = New SqlConnection(DBConnection)
        Dim ds As DataSet = New DataSet
        Dim da As SqlDataAdapter = New SqlDataAdapter
        da.SelectCommand = cmd
        da.Fill(ds)
        Dim dt As DataTable = ds.Tables(0)

        ' create an XmlDocument (with an XML declaration)
        Dim XDoc As New XmlDocument()
        Dim XDec As XmlDeclaration = XDoc.CreateXmlDeclaration("1.0", Nothing, Nothing)
        XDoc.AppendChild(XDec)

        ' iterate through the sorted data
        ' and build the XML document
        For Each Row As DataRow In dt.Rows
            ' create an element node to insert
            ' note: Element names may not have spaces so use ID
            ' note: Element names may not start with a digit so add underscore
            Dim NewNode As XmlElement = XDoc.CreateElement("_" & Row("NodeID").ToString())
            NewNode.SetAttribute("NodeID", Row("NodeID").ToString())
            NewNode.SetAttribute("ParentID", Row("ParentID").ToString())
            NewNode.SetAttribute("title", Row("title").ToString())

            ' special case for top level node
            If IsDBNull(Row("ParentID")) Then
                XDoc.AppendChild(NewNode)
            Else
                ' root node
                ' use XPath to find the parent node in the tree
                Dim SearchString As [String]
                SearchString = [String].Format("//*[@NodeID=""{0}""] ", Row("ParentID").ToString())
                Dim Parent As XmlNode = XDoc.SelectSingleNode(SearchString)

                If Parent IsNot Nothing Then
                    Parent.AppendChild(NewNode)
                Else

                    ' Handle Error: Employee with no boss
                End If
            End If
        Next
        XDoc.Save(Server.MapPath("~/menu/menu.xml"))
In tal modo nella cartella menu della nostra applicazione verrà generato il file menu.xml così fatto:
<?xml version="1.0"?>
<_1 NodeID="1" ParentID="0" title="Root">
  <_2 NodeID="2" ParentID="1" title="item 1">
    <_3 NodeID="3" ParentID="2" title="item 1.1" />
    <_4 NodeID="4" ParentID="2" title="item 1.2" >
      <_5 NodeID="5" ParentID="5" title="item 1.2.1" />
    </_4>
    <_6 NodeID="6" ParentID="2" title="1.3" />
  </_2>
  <_7 NodeID="7" ParentID="1" title="item 2"/>
</_1>
Vogliamo ora trasformare la struttura XML in una stringa HML così fatta:
<li><a name="_2" href="#">item 1</a>
   <ul>
      <li><a name="_3" href="page.aspx?nodeID=3">item 1.1</a></li>
      <li><a name="_4" href="#">item 1.2</a>
         <ul>
            <li><a name="_5" href="page.aspx?nodeID=5">item 1.2.1</a>
         </ul>
      </li>
      <li><a name="_6" href="page.aspx?nodeID=6">item 1.3</a></li>
   </ul>
</li>
<li><a name="_7" href="page.aspx?nodeID=7">item 2</a></li>
Definiamo quindi il seguente file XSLT di trasformazione e memorizzaiamolo nella cartella "menu" con il nome menu.xslt
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>


    <!--The <xsl:template> element contains rules to apply when a specified node is matc-->
    <xsl:template match="node()">
        
        <!--calcola il numero di nodi figli dell'elemento corrente-->
        <xsl:variable name="total-el">
            <xsl:value-of select="count(descendant::*)"/>
        </xsl:variable>

        <xsl:variable name="name">
            <xsl:value-of select="name()"/>
        </xsl:variable>       
            
        <!--se il nodo nonè la root ed il numero di nodi figlio è >0 allora applica il seguente modello ai nodi figlio dell'elemento corrente..-->

            <xsl:if test="$total-el > 0 and $name != '_1'">
                <li>
                    <a name="{name()}" href="#" rel="self">
                        <xsl:value-of select="@NodeHTML"/>
                    </a>
                    <ul>
                        <xsl:apply-templates />
                    </ul>
                </li>
            </xsl:if>


            <xsl:if test="$total-el > 0 and $name = '_1'">
                    <ul class="topnav">
                        <xsl:apply-templates />
                    </ul>
            </xsl:if>      
        
            <!--altrimenti ...-->
            <xsl:if test="$total-el = 0">
                <li>
                    <a name="{name()}" href="articles.aspx?NodeID={name()}">
                        <xsl:value-of select="@NodeHTML"/>
                    </a>
                </li>
            </xsl:if>


    </xsl:template>

</xsl:stylesheet>
Non ci resta infine che applicare la trasformazione mediante il segunte codice:
Dim xDoc As New XmlDocument()
xDoc.Load(Server.MapPath("~/menu/menu.xml"))
Dim sw As New System.IO.StringWriter()
Dim xslTrans As New XslCompiledTransform()
xslTrans.Load(Server.MapPath("~/menu/menu.xslt"))
xslTrans.Transform(xDoc.CreateNavigator(), New XsltArgumentList(), sw)

Using writer As System.IO.StreamWriter = System.IO.File.AppendText(HttpRuntime.AppDomainAppPath & "menu\menu.txt")
   writer.WriteLine(sw.ToString())
End Using
producendo nel file menu.txt nella cartella menu il codice html desiderato.

Come mantenere invariato il formato valuta in ASP.NET in un'applicazione multi lingua

Le impostazioni linguistiche in una pagina ASP.NET sono dipendenti da due proprietà: Culture e UICulture. 
La proprietà Culture deterimina il risultato delle funzioni dipendenti dalle impostazioni lingiuistiche come ad esempio l'uso delle maiuscole e delle minuscole, la formattazione di date e numeri, il formato della valutam, il confronto tra stringhe ecc...
La proprietà UICulture determina quali risorse devono essere caricate per la pagina.
Da questa premessa è quindi semplice comprendere come è possibile mantenere invariato il formato della valuta in un'applicazione multilingua: sarà sufficiente infatti mantenere costante il valore della proprietà Culture e cambiare la propietà UICulture per caricare di volta in volta le risorse della pagina in base alla lingua selezionata.
Ciò è possibile  eseguendo l'override del metodo InitializeCulture in ogni pagina dell'applicazione. Volendo quindi mantenere costante il formato della valuta all'€, per ogni pagina sarà sufficiente richiamare la seguente Sub:
Protected Overrides Sub InitializeCulture()
        ' Culture: valore costante
        Thread.CurrentThread.CurrentCulture = New CultureInfo("it-IT")

        ' UI Culture: valore contenuto nella variabile di Sessione Session("UICulture")
        Dim c As CultureInfo
        If Session("UICulture") IsNot Nothing Then
            c = DirectCast(Session("UICulture"), CultureInfo)
        Else
            c = New CultureInfo("it-IT")
        End If

        Thread.CurrentThread.CurrentUICulture = c

        MyBase.InitializeCulture()
    End Sub
in cui il valore di UICulture è determinato dalla variabile di Sessione UICulture in modo che diventi comune a tutte le pagine.

Abilitare il Full-Text Search in SQL Server 2008 Express

In SQL SERVER 2008 Express, la caratteristica  Full-Text Search è disponibile solo nella versione "Microsoft SQL Server 2008 Express with Advanced Services" scaricabile all'indirizzo http://www.microsoft.com/downloads/it-it/details.aspx?FamilyID=B5D1B8C3-FDA5-4508-B0D0-1311D670E336

Segnalo che per abilitare il Full-Text Search non è possibile eseguire l'upgrade di una installazione eseguita da una versione di SQL Server Express differente dalla sopra citata.

Per cui per fruire della caratteristica Full-Text Search si deve eseguire una nuova installazione di SQL Server Express utilizzando il download eseguito da Microsoft.

I problemi di incompatibilità eventualmente rilevati nell'installazione possono essere tralasciati; la soluzione indicata, ovvero l'applicazione del Service Pack 1, non è applicabile per la versione "Microsoft SQL Server 2008 Express with Advanced Services" in quanto il Serviche Pack 1 non è corredato dei Servizi avanzati utili per abilitare il Full-Text Search.

 

SharePoint Foundation: Service Unavailable

Visualizzando un sito web di Sharepoint Foundation, il browser mi restituiva l'errore: Servzio non disponible. L'errore era dal mio punto di vista del tutto ingiustificato in quanto il sito funzionava bene fino ad un'ora prima.

Analizzando il pool di applicaione mediante IIS manager ho notato che le applicazioni correlate con il mio sito non erano avviate ed anche riavviandole, appena dopo il tentativo di visitare il sito venivano di nuovo arrestate.

Dalle proprietà  dell'applicazione sono risalito all'identità di gestione dell'applicazione ... identità a cui avevo modificato la password poco prima!

Eureka! Il problema era proprio dovuto alla modifica della password.

Infatti dalle Proprietà Avanzate dell'Applicazione mi è stato possibile rinserire la nuova password dell'utente e riavviare con successo l'applicazione.

L'articolo di riferimento del supporto tecnico Microsoft è: http://support.microsoft.com/kb/823552

 

Creare un meccanismo di autentificazione Forms-Based per un'applicazione SharePoint Foundation utilizzando il Membership ed il Role Providers di ASP.NET SQL

Premessa doverosa: per raggiungere l'obiettivo del titolo di questo post ho impiegato più di 8 ore di lavoro leggendo e rileggendo documentazione tecnica Microsoft, blog tecnici e quanto altro. Spero che il mio post sia di aiuto a molti lettori; comunque lo sarà per me nei prossimi deployment. Il documento MSDN che prenderò come riferimento è il seguente http://msdn.microsoft.com/en-us/library/gg252020.aspx (che deve essere adattata per Sharepoint Foundation). Allo stesso modo suddividerò la trattazione per passi successivi.
 

STEP 1: Preparazione del Database al fine di utilizzare il Membership ed il Role Provider ASP.NET per le applicazioni web

Eseguiamo il file aspnet_regsql.exe contenuto nella cartella C:\Windows\Microsoft.NET\Framework64\v2.0.50727. Verrà avviata una procedura guidata che consentirà facilmente di creare il database che verrà utilizzando dal Provider. Sarà sufficiente selezionare l'istanza del Server di Database (WIN-02F9XCJAEJX\SQLEXPRESS nel mio caso) ed assegnare il nome al database (aspnetdb_claim)

STEP 2: Aggiungere utenti e ruoli al Database del Provider dei Ruoli e dei Membri

Avviare Microsoft SQL Server Management Studio ed eseguire le seguenti query sul db aspnetdb_claim database:
declare @now datetime
set @now= GETDATE()
exec aspnet_Membership_CreateUser 'MyAppName','admin','pwadmin',
    '','admin1@contoso.com','','',1,@now,@now,0,0,null
 
EXEC aspnet_Roles_CreateRole 'MyAppName', 'Administrator'
EXEC aspnet_UsersInRoles_AddUsersToRoles 'MyAppName', 'admin', 'Administrator', 8
 

STEP 3: Creare un'applicazione di Sharepoint Foundation

 
Seguire la seguente procedura
  1. Aprire SharePoint 2010 Central Administration
  2. In Application Management section, cliccare su Manage web applications.
  3. Sulla ribbon (striscia superiore della finestra) cliccare su New. Si creerà una nuova applicazione con dei valori default: assumiamo in questo esempio che la porta sia la numero 8676 e l'url pubblico sia http://WIN-02F9XCJAEJX:8676/ (WIN-02F9XCJAEJX è il nome del server dove state eseguendo il deployment)
  4. Nella finestra di dialogo, nella sezione Authentication, scegliere Claims Based Authentication.
  5. In Claims Authentication Types section, selezionare Enable Forms Based Authentication (FBA) e deselezionare tutte le altre opzioni (in particolare Enable Windows Authentication e Integrated Windows authentication)
  6. Nella casella di testo "ASP.NET membership provider name" immettere aspnetmembership, nel campo "ASP.NET role manager name" svrivere  aspnetrolemanager
  7. Nella sezione "Database Name and Authentication", cambiare il nome del db da WSS_Content a WSS_Content_8676 ed assicurarsi che il database server sia WIN-02F9XCJAEJX\Sqlexpress, dove abbiamo creato il dabase dei ruoli e membri.
  8. Lasciare le altre opzioni invariate

STEP 4: Configurare il Membership ed il Role Provider per l'applicazione Sharepoint Foundation

Questo step prevede la modifica di:
  1. Central Administration
  2. Security Token Service
  3. FBA Web Application
E' necessario innanzitutto identificare il web.config della SharePoint 2010 Central Administration: a tal proposito è possibile ad esempio servirsi di IIS Manager ed espolare il sito "SharePoint Central Administration v4". Nel mio caso la directory di appoggio della Central Administration si trova in C:\inetpub\wwwroot\wss\VirtualDirectories\32388.
Sostituire il web.config con web.config (46,21 kb). Di fatto sarebbe stato sufficiente inserire nel web.config la segunte stringa di connessione appena dopo </configSections>
<connectionStrings>
    <clear />
    <add name="AspNetSqlMembershipProvider" connectionString="data source=.\Sqlexpress;Integrated Security=SSPI;Initial Catalog=aspnetdb_claim"
      providerName="" />
    <add name="MyLocalSQLServer" connectionString="Initial Catalog=aspnetdb_claim;data source=.\Sqlexpress;Integrated Security=SSPI;" />
  </connectionStrings>
ed il seguente codicie
<roleManager enabled="true" cacheRolesInCookie="false" cookieName=".ASPXROLES"
      cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true"
      cookieProtection="All" defaultProvider="AspNetWindowsTokenRoleProvider"
      createPersistentCookie="false" maxCachedResults="25">
      <providers>
        <clear />
        <add connectionStringName="AspNetSqlMembershipProvider" applicationName="/"
          name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add applicationName="/" name="AspNetWindowsTokenRoleProvider"
          type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add name="aspnetrolemanager"
             type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName" />
      </providers>
    </roleManager>
    <membership defaultProvider="AspNetSqlMembershipProvider" userIsOnlineTimeWindow="15"
      hashAlgorithmType="">
      <providers>
        <clear />
        <add connectionStringName="AspNetSqlMembershipProvider" enablePasswordRetrieval="false"
          enablePasswordReset="true" requiresQuestionAndAnswer="true"
          passwordAttemptWindow="10" applicationName="/" requiresUniqueEmail="false"
          passwordFormat="Hashed" name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add name="aspnetmembership"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName"
             type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </membership>
nel <system.web>, andando a sostituire i tag <roleManager> e <membership> se già estenti.
Sempre mediante IIS identificare SharePoint Web Services ed esplorare SecurityTokenServiceApplication. Nel nostro caso si verrebbe reindirizzati alal seguente cartella C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\WebServices\.
Sostituire il web.config presente con web.config (6,73 kb), oppure aggiungere al web.config già presente il seguente codice appenda dopo <configuration>
<connectionStrings>
    <clear />
    <add name="AspNetSqlMembershipProvider" connectionString="data source=.\Sqlexpress;Integrated Security=SSPI;Initial Catalog=aspnetdb_claim"
      providerName="" />
    <add name="MyLocalSQLServer" connectionString="Initial Catalog=aspnetdb_claim;data source=.\Sqlexpress;Integrated Security=SSPI;" />
  </connectionStrings>
e la sezione seguente appena prima di </configuration>:
<system.web>
    <roleManager enabled="true" cacheRolesInCookie="false" cookieName=".ASPXROLES" cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="All" createPersistentCookie="false" maxCachedResults="25">
      <providers>
        <add connectionStringName="AspNetSqlMembershipProvider" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add name="aspnetrolemanager" 
             type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName" />
      </providers>
    </roleManager>
    <membership userIsOnlineTimeWindow="15" hashAlgorithmType="">
      <providers>
        <add connectionStringName="AspNetSqlMembershipProvider" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" passwordAttemptWindow="10" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
 	<add name="aspnetmembership"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName"
             type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </membership>
 </system.web>
Infine è necessario sostituire il web.config della nostra applicazione web allocata in C:\inetpub\wwwroot\wss\VirtualDirectories\8676 con web.config (48,19 kb) o in alternativa modificare il file di configurazione già presente aggiungendo:
<connectionStrings>
    <add name="MyLocalSQLServer" connectionString="data source=.\Sqlexpress;Integrated Security=SSPI;Initial Catalog=aspnetdb_claim" providerName="" />
  </connectionStrings>
subito dopo </configSections> e
<membership defaultProvider="i">
      <providers>
        <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="aspnetmembership" connectionStringName="MyLocalSQLServer" applicationName="MyAppName" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </membership>
    <roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
      <providers>
        <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="aspnetrolemanager" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="MyLocalSQLServer" applicationName="MyAppName" />
      </providers>
    </roleManager>
appena prima di </system.web>, sostituendo nel caso in cui esistano i tag già presenti.
 

STEP 5: Testare il modello di autentificazione

Utilizzando la Central Administration website, sotto Application Management cliccare su Create site collection.
Nella casella a discesa Web Application selezionare la nostra applicazione, http://WIN-02F9XCJAEJX:8676/ e quindi assegnare un titolo al sito. Nella texbox User name scrivere admin, ovvero il nome dell'utente che abbiamo inserito nel DB e controllare l'esistenza dell'utente.
Confermare la creazione del sito e nel browser digitare http://WIN-02F9XCJAEJX:8676/ . Se tutto funziona si viene reindirizzati ad una pagina di login dove si deve inserire lo user name admin e la password pwadmin.

STEP 6: Risolvere gli eventuali problemi

Il problema che io ho incontrato era legato alla non attivazione di Security Token Service Application . 

La risoluzione del problema è descritta nel seguente articolo http://support.microsoft.com/kb/2520344. In particolare ho dovuto assegnare al sito il livello di Trust Full.

Ottenere il PublicKeyToken di una dll

Per ricavare il Public Key Token di un assembly .NET è sufficiente utilizzare gli strumenti esterni di Visual Studio come recita il seguente articolo http://blogs.msdn.com/b/kaevans/archive/2008/06/18/getting-public-key-token-of-assembly-within-visual-studio.aspx.

Per chi come il sottoscritto utilizza Visual Web Developer Express, il metodo non è utilizzabile perché vincolato dal possesso di Visual Studio.

Un metodo semplice e a costo zero sussiste nell'accedere al direttorio C:\Windows\assembly e visualizzare le proprietà delle dll installate.

Nel caso in cui la dll non risultasse installata e quindi non fosse presente, sarebbe sufficiente "trascinarla" nel direttorio sopra menzionato.

Ottenere la versione di una dll

Per ottenere la versione di una dll è sufficiente creare il seguente file vbs utilizzando ad esempio blocco note:
set args = WScript.Arguments
Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetFileVersion(args(0))
Wscript.Quit
Salvare quindi il file con nome, ad esempio VersionInfo.vbs, in un direttorio qualsiasi
Aprire l'interfaccia a riga di comando (cmd.exe) ed eseguire dal path in cui si è salvato il file vbs:
cscript //nologo VersionInfo.vbs C:\Path\To\MyFile.dll
in cui MyFile.dll è la dll di cui si vuole conoscere la versione

SharePoint Foundation 2010: la mia prima installazione

C'è sempre una prima volta e per il sottoscritto oggi rappresenta l'iniziazione alla piattaforma Sharepoint che spero mi aprirà nuovi scenari di applicazione e sviluppo.

Di fatto già un anno fa mi ero sperimentato nell'utilizzo di Sharepoint acquistando un servizio hostato su http://www.apps4rent.com/.

Oggi invece ho installato SharePoint Foundation 2010 e l'SDK relativo sul mio notebook con sistema operativo Windows 7 Pro. Ho seguito come linea guida per l'installazione le seguenti istruzioni di Microsoft http://msdn.microsoft.com/en-us/library/ee554869.aspx.

Ora mi attende l'installazione sul server web di distribuzione ...

Google Maps Latitude, Longitude Grabber with Geocoding and Reverse Geocoding using Google Maps Javascript API V3 Services

Mi sto occupando dello sviluppo di un CMS per la gestione di SlideCake (www.slidecake.com). Ho così progettato una sezione per la modifica delle slide di tipo Google Maps utilizzando le API v3.

Alla seguente pagina http://www.sormanistudio.it/gmap/smap.htm è possibile testare la funzionalità "cuore" dell'applicazione. E' così possibile inserire l'indirizzo della location ed il codice si occuperà di geo-localizzare il punto restituendo la latitudine e longitudine dell'indirizzo.

Oppure inserendo le coordinate geografiche il servizio collocherà il luogo sulla mappa restituendo l'indirizzo (geo-localizzazione inversa) ed infine cliccando semplicemente sulla mappa verranno visualizzate le coordinate del punto e l'indirizzo esatto.

All'indirizzo http://www.sormanistudio.it/gmap/smap.zip sono disponibili in download i file sorgenti dell'applicazione.