Opzioni di spostamento per SharePoint Online

Importante :  Il presente articolo è stato tradotto automaticamente, vedere la dichiarazione di non responsabilità. Per visualizzare la versione inglese dell'articolo, fare clic qui.

Questo articolo spiega come migliorare i tempi di caricamento delle pagine per SharePoint Online usando l'esplorazione strutturale e l'esplorazione basata sulla ricerca.

La struttura di spostamento globale e le query necessarie per creare l'esplorazione strutturale possono rallentare il caricamento delle pagine in SharePoint Online. Ciò avviene perché ognuna di queste query invia un'altra richiesta a SQL Server. Per ogni sito e sito secondario esistente vengono infatti inviate più richieste a SQL Server. Questo problema riguarda anche le pagine master e di conseguenza la struttura di spostamento globale.

Con alcuni siti di SharePoint sono necessarie strutture complesse e di grandi dimensioni. Con l'esplorazione strutturale predefinita, che usa query contenuto, i tempi di caricamento delle pagine possono allungarsi perché esistono più livelli dei siti. Viene creata un'altra query anche per ognuno dei livelli dei siti secondari.

In SharePoint sono disponibili due opzioni di esplorazione predefinite principali, oltre a un terzo approccio personalizzato basato sulla ricerca. Ogni opzione presenta vantaggi e svantaggi, come illustrato nella tabella seguente.

Esplorazione strutturale

Esplorazione gestita

Esplorazione basata sulla ricerca

Vantaggi:

  • Facilmente configurabile

  • Limitazione per motivi di sicurezza

  • Aggiornamento automatico dopo l'aggiunta di siti

Vantaggi:

  • Facilmente gestibile

Vantaggi:

  • Limitazione per motivi di sicurezza

  • Aggiornamento automatico dopo l'aggiunta di siti

  • Tempo di caricamento ridotto e struttura di spostamento memorizzata nella cache locale

Svantaggi:

  • Prestazioni insufficienti se la struttura del sito è complessa

Svantaggi:

  • Nessun aggiornamento automatico in base alla struttura del sito

Svantaggi:

  • Impossibilità di ordinare facilmente i siti

  • Richiede la personalizzazione della pagina master (necessarie competenze tecniche)

Se si ha un sito con molti siti secondari e si usa l'esplorazione strutturale, il tempo di caricamento delle pagine potrebbe aumentare considerevolmente. L'opzione più appropriata per il sito varia a seconda dei requisiti specifici del sito e delle capacità tecniche disponibili. Se si preferisce usare una pagina master personalizzata e nell'organizzazione sono disponibili funzionalità per gestire le modifiche che potrebbero essere apportate alla pagina master predefinita di SharePoint Online, l'opzione basata su ricerca consente di offrire un'esperienza utente ottimale. Se si preferisce una soluzione semplice intermedia l'esplorazione strutturale predefinita e quella basata sulla ricerca, l'esplorazione gestita costituisce una validissima opzione. L'esplorazione gestita può infatti essere gestita tramite configurazione, non implica l'uso di file di personalizzazione del codice ed è significativamente più rapida dell'esplorazione strutturale predefinita.

Un altro approccio consiste nel ristrutturare il sito esistente e ridurre il numero di elementi della struttura di spostamento e dei siti secondari necessari. L'esplorazione strutturale funziona infatti correttamente purché la struttura del sito e la struttura di spostamento non siano troppo complicate.

Questo articolo mette a confronto i vari approcci in una raccolta siti di esempio. La raccolta siti di esempio include 11 siti secondari, ognuno dei quali contiene almeno quattro siti secondari aggiuntivi.

Screenshot che mostra i siti e siti secondari

Uso dell'esplorazione strutturale in SharePoint Online

Si tratta della struttura di spostamento usata per impostazione predefinita ed è la soluzione più semplice e appropriata nella maggior parte dei casi. A meno che non si tratti di una struttura complessa composta da più siti secondari o molti livelli di siti secondari, l'esplorazione strutturale è una soluzione ottimale. Questo approccio offre numerosi vantaggi, tra cui la limitazione per motivi di sicurezza e l'aggiornamento automatico in seguito all'aggiunta di nuovi siti, oltre a non richiedere la personalizzazione della pagina master. Un utente non tecnico può inoltre aggiungere elementi, nascondere elementi e gestire la struttura di spostamento dalla pagina delle impostazioni.

Attivazione dell'esplorazione strutturale in SharePoint Online

Per illustrare le prestazioni in una soluzione standard di SharePoint Online con l'esplorazione strutturale e l'opzione Mostra i siti secondari attivata, è possibile esaminare le impostazioni dello screenshot seguente visualizzato nella pagina Impostazioni sito > Struttura di spostamento.

Screenshot che mostra i siti secondari

Analisi delle prestazioni dell'esplorazione strutturale in SharePoint Online

Per analizzare le prestazioni di una pagina di SharePoint, usare la scheda Rete di Strumenti di sviluppo F12 in Internet Explorer.

Screenshot della scheda Rete di Strumenti di sviluppo F12

Nella scheda Rete fare clic sulla pagina con estensione aspx di cui è in corso il caricamento e quindi fare clic sulla scheda Dettagli.

Screenshot della scheda Dettagli

Fare clic su Intestazioni risposte.

Screenshot della scheda Dettagli

SharePoint restituisce alcune utili informazioni diagnostiche nelle intestazioni delle risposte. Una delle intestazioni più utili è SPRequestDuration   , che corrisponde al valore in millisecondi relativo al tempo di elaborazione di una richiesta nel server.

Nello screenshot seguente l'opzione Mostra i siti secondari è deselezionata per l'esplorazione strutturale. Questo significa che nella struttura di spostamento globale esiste solo il collegamento della raccolta siti:

Screenshot che mostra i tempi di caricamento come durata della richiesta

Il valore della chiave SPRequestDuration    è pari a 245 millisecondi e rappresenta il tempo necessario per restituire la richiesta. Dal momento che nel sito è presente un unico elemento della struttura di spostamento, questo costituisce un valido riferimento per valutare le prestazioni di SharePoint Online in assenza di una struttura di spostamento complessa. Lo screenshot successivo mostra l'impatto dell'aggiunta di siti secondari su questa chiave.

Screenshot che mostra una richiesta con una durata di 2502 ms

In seguito all'aggiunta dei siti secondari, il tempo necessario per restituire la richiesta della pagina è notevolmente aumentato.

L'esplorazione strutturata normale offre numerosi vantaggi. È ad esempio possibile organizzare l'ordine, nascondere i siti e aggiungere pagine. È inoltre prevista la limitazione dei risultati per motivi di sicurezza e non è necessario modificare le pagine master supportate usate in SharePoint Online. Per ottimizzare le prestazioni dell'esplorazione strutturale, è necessario strutturare attentamente il sito e ridurre al minimo il numero di siti secondari nella raccolta siti.

Uso dell'esplorazione gestita e dei metadati gestiti in SharePoint Online

L'esplorazione gestita è un'altra opzione predefinita che è possibile usare per ricreare lo stesso tipo di funzionalità dell'esplorazione strutturale.

L'uso dei metadati gestiti offre numerosi vantaggi, tra cui la maggior velocità nel recupero dei dati rispetto alla query contenuto per creare la struttura di spostamento del sito. Anche se più veloce, questa soluzione non prevede la possibilità di limitare i risultati per motivi di sicurezza, di conseguenza se un utente non ha accesso a un determinato sito, il collegamento verrà comunque visualizzato, ma verrà restituito un messaggio di errore.

Come implementare l'esplorazione gestita e i risultati   

Esistono diversi articoli su TechNet dei dettagli relativi a esplorazione gestita, ad esempio, vedere Panoramica di esplorazione gestita in SharePoint Server 2013.

Per implementare l'esplorazione gestita, è necessario avere le autorizzazioni di amministratore dell'archivio termini. Configurando termini con URL corrispondenti alla struttura di una raccolta siti, è possibile usare l'esplorazione gestita in sostituzione dell'esplorazione strutturale. Ad esempio:

Screenshot dell'esempio Sito secondario 1

L'esempio seguente mostra le prestazioni della struttura di spostamento complessa con l'esplorazione gestita.

Screenshot dell'esempio SPRequestDuration

L'uso coerente dell'esplorazione gestita consente di migliorare le prestazioni rispetto all'approccio basato sull'esplorazione strutturale con query contenuto.

Uso di script lato client basati sulla ricerca

La funzionalità di ricerca consente di sfruttare gli indici creati in background tramite la ricerca per indicizzazione continua. Di conseguenza non vengono più usate query contenuto pesanti. I risultati della ricerca vengono recuperati dall'indice di ricerca e sono soggetti alla limitazione per motivi di sicurezza. Questo approccio è più rapido rispetto all'uso delle normali query contenuto. L'uso della ricerca per l'esplorazione strutturale, in particolare se la struttura del sito è complessa, consentirà di ridurre notevolmente i tempi di caricamento delle pagine. Il principale vantaggio di questo approccio rispetto all'esplorazione gestita è costituito dalla possibilità di applicare la limitazione per motivi di sicurezza.

Questo approccio implica la creazione di una pagina master personalizzata e la sostituzione del codice della struttura di spostamento predefinito con codice HTML personalizzato. Eseguire questa procedura per sostituire il codice della struttura di spostamento nel file seattle.html.

In questo esempio si aprirà il file seattle.html e si sostituirà l'intero elemento id=”DeltaTopNavigation” con codice HTML personalizzato.

Esempio: Per sostituire il codice della casella spostamento in una pagina master

  1. Passare alla pagina Impostazioni sito.

  2. Per aprire la Raccolta pagine master, fare clic su Pagine master.

  3. Da qui è possibile spostarsi nella raccolta e scaricare il file seattle.master.

  4. Per modificare il codice, usare un editor di testo ed eliminare il blocco di codice nello screenshot seguente.

    Screenshot del codice DeltaTopNavigation da eliminare
  5. Rimuovere il codice tra i tag <SharePoint:AjaxDelta id=”DeltaTopNavigation”> e <\SharePoint:AjaxDelta> e sostituirlo con il frammento seguente:

    <div id="loading">
      <!--Replace with path to loading image.-->
      <div style="background-image: url(''); height: 22px; width: 22px; ">
      </div>
    </div>
    <!-- Main Content-->
    <div id="navContainer" style="display:none">
        <div data-bind="foreach: hierarchy" class="noindex ms-core-listMenu-horizontalBox">
            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                <span class="menu-item-text" data-bind="text: item.Title">
                </span>
            </a>
            <ul id="menu" data-bind="foreach: $data.children" style="padding-left:20px">
                <li class="static dynamic-children">
                    <a class="static dynamic-children menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                        <span aria-haspopup="true" class="additional-background ms-navedit-flyoutArrow dynamic-children">
                            <span class="menu-item-text" data-bind="text: item.Title">
                            </span>
                        </span>
                    </a>
                    <ul id="menu" data-bind="foreach: children; visible: children.length>0" class="dynamic" >
                        <li class="dynamic">
                            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                                <span class="menu-item-text" data-bind="text: item.Title">
                                </span>
                            </a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
  6. Sostituire l'URL di caricamento immagine tag di ancoraggio all'inizio, con un collegamento a un'immagine nella raccolta siti. Dopo avere apportato le modifiche, rinominare il file e quindi caricarlo nella raccolta pagine master. Verrà generato un nuovo file con estensione master.

  7. Questo codice HTML è il markup di base che verrà prepopolato con i risultati della ricerca restituiti dal codice JavaScript. Per cambiare il valore di var root = “site collection URL, sarà necessario modificare il codice seguente come illustrato nel frammento seguente:

    var root = “https://spperformance.sharepoint.com/sites/NavigationBySearch”;

    Il file JavaScript completo è il seguente:

    //Models and Namespaces
    var SPOCustom = SPOCustom || {};
    SPOCustom.Models = SPOCustom.Models || {}
    SPOCustom.Models.NavigationNode = function () {
    
        this.Url = ko.observable("");
        this.Title = ko.observable("");
        this.Parent = ko.observable("");
    
    };
    
    var root = "https://spperformance.sharepoint.com/sites/NavigationBySearch";
    var baseUrl = root + "/_api/search/query?querytext=";
    var query = baseUrl + "'contentClass=\"STS_Web\"+path:" + root + "'&trimduplicates=false&rowlimit=300";
    
    var baseRequest = {
        url: "",
        type: ""
    };
    
    
    //Parses a local object from JSON search result.
    function getNavigationFromDto(dto) {
        var item = new SPOCustom.Models.NavigationNode();
        if (dto != undefined) {
    
            var webTemplate = getSearchResultsValue(dto.Cells.results, 'WebTemplate');
    
            if (webTemplate != "APP") {
                item.Title(getSearchResultsValue(dto.Cells.results, 'Title')); //Key = Title
                item.Url(getSearchResultsValue(dto.Cells.results, 'Path')); //Key = Path
                item.Parent(getSearchResultsValue(dto.Cells.results, 'ParentLink')); //Key = ParentLink
            }
    
        }
        return item;
    }
    
    function getSearchResultsValue(results, key) {
    
        for (i = 0; i < results.length; i++) {
            if (results[i].Key == key) {
                return results[i].Value;
            }
        }
        return null;
    }
    
    //Parse a local object from the serialized cache.
    function getNavigationFromCache(dto) {
        var item = new SPOCustom.Models.NavigationNode();
    
        if (dto != undefined) {
    
            item.Title(dto.Title);
            item.Url(dto.Url);
            item.Parent(dto.Parent);
        }
    
        return item;
    }
    
    /* create a new OData request for JSON response */
    function getRequest(endpoint) {
        var request = baseRequest;
        request.type = "GET";
        request.url = endpoint;
        request.headers = { ACCEPT: "application/json;odata=verbose" };
        return request;
    };
    
    /* Navigation Module*/
    function NavigationViewModel() {
        "use strict";
        var self = this;
        self.nodes = ko.observableArray([]);
        self.hierarchy = ko.observableArray([]);;
        self.loadNavigatioNodes = function () {
            //Check local storage for cached navigation datasource.
            var fromStorage = localStorage["nodesCache"];
            if (false) {
                var cachedNodes = JSON.parse(localStorage["nodesCache"]);
    
                if (cachedNodes && timeStamp) {
                    //Check for cache expiration. Currently set to 3 hrs.
                    var now = new Date();
                    var diff = now.getTime() - timeStamp;
                    if (Math.round(diff / (1000 * 60 * 60)) < 3) {
    
                        //return from cache.
                        var cacheResults = [];
                        $.each(cachedNodes, function (i, item) {
                            var nodeitem = getNavigationFromCache(item, true);
                            cacheResults.push(nodeitem);
                        });
    
                        self.buildHierarchy(cacheResults);
                        self.toggleView();
                        addEventsToElements();
                        return;
                    }
                }
            }
            //No cache hit, REST call required.
            self.queryRemoteInterface();
        };
    
        //Executes a REST call and builds the navigation hierarchy.
        self.queryRemoteInterface = function () {
            var oDataRequest = getRequest(query);
            $.ajax(oDataRequest).done(function (data) {
                var results = [];
                $.each(data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results, function (i, item) {
    
                    if (i == 0) {
                        //Add root element.
                        var rootItem = new SPOCustom.Models.NavigationNode();
                        rootItem.Title("HSHSL");
                        rootItem.Url(root);
                        rootItem.Parent(null);
                        results.push(rootItem);
                    }
                    var navItem = getNavigationFromDto(item);
                    results.push(navItem);
                });
                //Add to local cache
                localStorage["nodesCache"] = ko.toJSON(results);
    
                localStorage["nodesCachedAt"] = new Date().getTime();
                self.nodes(results);
                if (self.nodes().length > 0) {
                    var unsortedArray = self.nodes();
                    var sortedArray = unsortedArray.sort(self.sortObjectsInArray);
    
                    var newItem = new SPOCustom.Models.NavigationNode();
                    newItem.Title("StaffHelp");
                    newItem.Url("https://staff.hshsl.umaryland.edu/staffhelp");
                    newItem.Parent(null);
                    sortedArray.push(newItem);
    
    
    
                    self.buildHierarchy(sortedArray);
                    self.toggleView();
                    addEventsToElements();
                }
            }).fail(function () {
                //Handle error here!!
                $("#loading").hide();
                $("#error").show();
            });
        };
        self.toggleView = function () {
            var navContainer = document.getElementById("navContainer");
            ko.applyBindings(self, navContainer);
            $("#loading").hide();
            $("#navContainer").show();
    
        };
        //Uses linq.js to build the navigation tree.
        self.buildHierarchy = function (enumerable) {
            self.hierarchy(Enumerable.From(enumerable).ByHierarchy(function (d) {
                return d.Parent() == null;
            }, function (parent, child) {
                if (parent.Url() == null || child.Parent() == null)
                    return false;
                return parent.Url().toUpperCase() == child.Parent().toUpperCase();
            }).ToArray());
    
            self.sortChildren(self.hierarchy()[0]);
        };
    
    
        self.sortChildren = function (parent) {
    
            // sjip processing if no children
            if (!parent || !parent.children || parent.children.length === 0) {
                return;
            }
    
            parent.children = parent.children.sort(self.sortObjectsInArray2);
    
            for (var i = 0; i < parent.children.length; i++) {
                var elem = parent.children[i];
    
                if (elem.children && elem.children.length > 0) {
                    self.sortChildren(elem);
                }
            }
        };
    
        // ByHierarchy method breaks the sorting in chrome and firefix 
        // we need to resort  as ascending
        self.sortObjectsInArray2 = function (a, b) {
            if (a.item.Title() > b.item.Title())
                return 1;
            if (a.item.Title() < b.item.Title())
                return -1;
            return 0;
        };
    
    
        self.sortObjectsInArray = function (a, b) {
            if (a.Title() > b.Title())
                return -1;
            if (a.Title() < b.Title())
                return 1;
            return 0;
        }
    }
    
    //Loads the navigation on load and binds the event handlers for mouse interaction.
    function InitCustomNav() {
        var viewModel = new NavigationViewModel();
        viewModel.loadNavigatioNodes();
    }
    
    function addEventsToElements() {
        //events.
        $("li.dynamic-children").mouseover(function () {
            var position = $(this).position();
            $(this).find("ul").css({ width: 125, left: position.left + 10, top: 50 });
    
        })
            .mouseout(function () {
                $(this).find("ul").css({ width: 0, left: -99999, top: 0 });
            });
    }
    
    _spBodyOnLoadFunctionNames.push("InitCustomNav");
    

    Per riepilogare il codice riportato sopra la funzione $(document).ready jQuery è presente un oggetto viewModel creato e quindi loadNavigationNodes() funzione sull'oggetto è chiamato. Questa funzione carica sia la gerarchia di navigazione compilato in precedenza memorizzata nell'archivio locale HTML5 del browser client o chiama la funzione queryRemoteInterface().

    QueryRemoteInterface() consente di creare una richiesta utilizzando la funzione getRequest() con il parametro di query definito in precedenza nello script e quindi restituisce i dati dal server. Questi dati sono essenzialmente una matrice di tutti i siti nella raccolta siti rappresentati come oggetti di trasferimento di dati con alcune proprietà. Questi dati, vengono analizzati negli oggetti definiti in precedenza SPO.Models.NavigationNode che utilizzano Knockout.js per creare proprietà visibile per l'utilizzo per i valori di associazione HTML definita in precedenza. Gli oggetti vengono quindi inseriti in una matrice di risultati. Questa matrice viene analizzata in JSON utilizzando ritaglio e archiviata in archiviazione browser locale per migliorare le prestazioni in futuro pagina Carica.

  8. Successivamente, i risultati vengono assegnati alla matrice self.nodes e viene creata una gerarchia fuori gli oggetti utilizzando linq.js assegnando l'output a una matrice self.heirarchy. Questa matrice è l'oggetto è associato al formato HTML. In tal caso nella funzione toggleView() passando l'oggetto automatico alla funzione ko.applyBinding() . Quindi, in questo modo la matrice di gerarchia da associare il codice HTML seguente:

    <div data-bind=”foreach: hierarchy” class=”noindex ms-core-listMenu-horizontalBox”>

    Infine, i gestori di mouseenter e mouseexit vengono aggiunti di spostamento del primo livello che viene eseguito nella funzione addEventsToElements() per gestire i menu a discesa sito secondario.

    I risultati della struttura di spostamento sono visibili nello screenshot seguente:

    Screenshot dei risultati del codice della struttura di spostamento

    Nell'esempio di struttura di spostamento complessa un caricamento di pagina nuovo senza memorizzazione nella cache locale indica che il tempo impiegato sul server è stato ridotto rispetto all'esplorazione strutturale di riferimento per ottenere un risultato analogo a quello dell'approccio con esplorazione gestita.

    Screenshot di SPRequestDuration 301

    Uno dei principali vantaggi di questo approccio è che, grazie all'archivio locale HTML5, la struttura di spostamento viene archiviata in locale e usata al successivo caricamento della pagina.

Per migliorare ulteriormente le prestazioni, è possibile usare l'API di ricerca per l'esplorazione strutturale, tuttavia questo approccio richiede alcune capacità tecniche per eseguire e personalizzare questa funzionalità. Nell'implementazione di esempio i siti sono ordinati alfabeticamente, come previsto dall'esplorazione strutturale predefinita. L'uso di un ordinamento diverso renderebbe più complicate le operazioni di sviluppo e gestione. Con questo approccio è inoltre necessario modificare le pagine master supportate. Se la pagina master personalizzata non viene gestita, il sito non potrà usufruire degli aggiornamenti e dei miglioramenti apportati da Microsoft alle pagine master.

Il codice precedente presenta le dipendenze seguenti:

La versione corrente di LinqJS non contiene il metodo ByHierarchy utilizzato nel codice precedente e interrompe il codice di struttura di spostamento. Per risolvere il problema, aggiungere il metodo seguente al file Linq.js prima della riga "Flatten: funzione ()".

ByHierarchy: function(firstLevel, connectBy, orderBy, ascending, parent) {
     ascending = ascending == undefined ? true : ascending;
     var orderMethod = ascending == true ? 'OrderBy' : 'OrderByDescending';
     var source = this;
     firstLevel = Utils.CreateLambda(firstLevel);
     connectBy = Utils.CreateLambda(connectBy);
     orderBy = Utils.CreateLambda(orderBy);
    
     //Initiate or increase level
     var level = parent === undefined ? 1 : parent.level + 1;

    return new Enumerable(function() {
         var enumerator;
         var index = 0;

        var createLevel = function() {
                 var obj = {
                     item: enumerator.Current(),
                     level : level
                 };
                 obj.children = Enumerable.From(source).ByHierarchy(firstLevel, connectBy, orderBy, ascending, obj);
                 if (orderBy !== undefined) {
                     obj.children = obj.children[orderMethod](function(d) {
                         return orderBy(d.item); //unwrap the actual item for sort to work
                     });
                 }
                 obj.children = obj.children.ToArray();
                 Enumerable.From(obj.children).ForEach(function(child) {
                     child.getParent = function() {
                         return obj;
                     };
                 });
                 return obj;
             };

        return new IEnumerator(

        function() {
             enumerator = source.GetEnumerator();
         }, function() {
             while (enumerator.MoveNext()) {
                 var returnArr;
                 if (!parent) {
                     if (firstLevel(enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }

                } else {
                     if (connectBy(parent.item, enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }
                 }
             }
             return false;
         }, function() {
             Utils.Dispose(enumerator);
         })
     });
 },

Nota : Dichiarazione di non responsabilità per la traduzione automatica: Il presente articolo è stato tradotto tramite un software di traduzione automatica e non da una persona. Microsoft offre le traduzioni automatiche per consentire a coloro che non conoscono la lingua inglese di leggere gli articoli sui prodotti, sui servizi e sulle tecnologie Microsoft. Dal momento che l'articolo è stato tradotto automaticamente, potrebbe contenere errori di sintassi, di grammatica o di utilizzo dei vocaboli.

Amplia le tue competenze
Esplora i corsi di formazione
Ottieni in anticipo le nuove caratteristiche
Partecipa al programma Office Insider

Queste informazioni sono risultate utili?

Grazie per i tuoi commenti e suggerimenti

Grazie per il tuo feedback! Potrebbe essere utile metterti in contatto con uno dei nostri operatori del supporto di Office.

×