Kaip: sąveikauti su išorinėmis paslaugomis naudojant serverio logiką

Šiame vadove nustatysite tinklalapį, kuris naudos serverio logiką išorinių tarnybų httpclient serverio objekto įrašams skaityti, rašyti, atnaujinti ir naikinti.

Pastaba.

Šiame pavyzdyje naudojama https://services.odata.org/TripPinRESTierService , bet galite naudoti kitus viešai prieinamus nemokamus testavimo įrankius.

1 veiksmas: sukurkite serverio logiką

  1. Prisijunkite prie "Power Pages".

  2. Pasirinkite svetainę + Redaguoti.

  3. Eikite į darbo sritį Nustatyti , tada pasirinkite Serverio logika (peržiūra)

    Ekrano kopija, kurioje rodoma, kur pasirinkti serverio logiką darbo srityje Nustatyti.

  4. Pasirinkti +Nauja serverio logika

  5. Įveskite serverio logikos pavadinimą. Šis pavadinimas naudojamas API kaip išteklių identifikatorius kuriant serverio logikos API. Pavyzdžiui:

    Ypatybė Vertės pavyzdys
    Pavadinimą services.odata.org
    Rodomas vardas Performing CRUD operations using OData service
  6. Pasirinkite + Įtraukti vaidmenis , kad priskirtumėte atitinkamą žiniatinklio vaidmenį. Pridėtas administratoriaus vaidmuo serverio logikoje Šiame pavyzdyje pasirinkite Administratoriai ir vėliau prisijunkite kaip administratorius, kad tęstumėte.

  7. Pasirinkite Įtraukti.

  8. Pasirinkite serverio logiką ir pasirinkite Redaguoti kodą.

    Pasirinkti redaguoti kodą

  9. Dialogo lange Redaguoti "Microsoft Visual Studio" žiniatinklio kodą pasirinkite Atidaryti "Visual Studio" kodą , kad sukurtumėte pasirinktinę logiką.

    Faile rasite iš anksto nustatytus metodus ir scenarijus.

  10. Apibrėžkite serverio loginį metodą, skirtą skaityti, redaguoti, kurti, naikinti operacijas naudojant išorinę paslaugą.

    Prieš get() metodą pridedama ši baseUrl konstanta

    
     const baseUrl  = "https://services.odata.org/TripPinRESTierService";
    
    
  11. Pakeiskite getfunkcijas , post, put, ir del pavyzdys šiuo kodu

    
    async function get() { 
       try { 
          Server.Logger.Log("GET called"); // Logger reference 
          if (!Server.Context.QueryParameters["username"]) { 
                const response = await Server.Connector.HttpClient.GetAsync( 
                   `${baseUrl}/People?$select=UserName,FirstName,LastName,MiddleName,Age`, 
                   {'content-type':'application/json'}); 
                return response; 
          } 
          else {             
                const id = Server.Context.QueryParameters["username"]; // Context reference 
                const response = await Server.Connector.HttpClient.GetAsync( 
                   `${baseUrl}(${id})/People?$select=UserName,FirstName,LastName,MiddleName,Age`, 
                   {'content-type':'application/json'}); 
                return response; 
          }         
       } catch (err) { 
          Server.Logger.Error("GET failed: " + err.message); 
          return JSON.stringify({ status: "error", method: "GET", message: err.message }); 
       } 
    } 
    
    async function post() { 
       try { 
          Server.Logger.Log("POST called"); 
          const data = JSON.parse(Server.Context.Body);            
          const url = `${baseUrl}/${data.serviceSession}/People`; 
          const { serviceSession, ...body } = data;  
          const response = await Server.Connector.HttpClient.PostAsync( 
                url,  
                JSON.stringify(body), 
                {'content-type':'application/json'}); 
          return response; 
       } catch (err) { 
          Server.Logger.Error("POST failed: " + err.message); 
          return JSON.stringify({ status: "error", method: "POST", message: err.message }); 
       } 
    }  
    
    async function put() { 
       try { 
          Server.Logger.Log("PUT called"); 
          const data = JSON.parse(Server.Context.Body);         
          const url = `${baseUrl}/${data.serviceSession}/People('${data.UserName}')`; 
          const { UserName, ...body1 } = data; 
          const { serviceSession, ...body } = body1; 
          const response = await Server.Connector.HttpClient.PatchAsync( 
                url,  
                JSON.stringify(body), 
                {'content-type':'application/json'}); 
          return response; 
       } catch (err) { 
          Server.Logger.Error("PUT failed: " + err.message); 
          return JSON.stringify({ status: "error", method: "PUT", message: err.message }); 
       } 
    }    
    
    async function del() { 
       try { 
          // "delete" keyword should not be used in script file. 
          Server.Logger.Log("DEL called"); 
          const username = Server.Context.QueryParameters["username"]; 
          const serviceSession = Server.Context.QueryParameters["serviceSession"]; 
          const url = `${baseUrl}/${serviceSession}/People('${username}')`; 
          const response = await Server.Connector.HttpClient.DeleteAsync( 
                url,  
                {'content-type':'application/json'}); 
          return response; 
       } catch (err) { 
          Server.Logger.Error("Deletion failed: " + err.message); 
          return JSON.stringify({ status: "error", method: "DEL", message: err.message }); 
       } 
    } 
    
  12. Įrašykite failą.

    Arbatpinigiai

    Norėdami išsaugoti, naudokite Ctrl+S .

2 veiksmas: sukurkite tinklalapį

  1. Paleiskite "Power Pages" dizaino studiją.

  2. Darbo srityje Puslapiai pasirinkite + Puslapis.

    Pridėti naują puslapį

  3. Dialogo lange Aprašyti puslapį, kad jį sukurtumėte , pasirinkite Kiti puslapio įtraukimo būdai.

  4. Dialogo lange Įtraukti puslapį įveskite išsamią informaciją.

    1. Lauke Pavadinimas įveskite Serverio logika ir pasirinkite Pradėti nuo tuščio maketo.
    2. Pasirinkite Įtraukti.

    Įveskite reikšmes, kad įtrauktumėte puslapį

  5. Viršutiniame dešiniajame kampe pasirinkite parinktį Redaguoti kodą .

  6. Dialogo lange Redaguoti žiniatinklio "Visual Studio" kodą pasirinkite Atidaryti "Visual Studio" kodą.

  7. Pakeiskite HTML puslapyje esantį kodą:

    <div class="row sectionBlockLayout text-left" style="min-height: auto; padding: 8px;">
    <div class="container" style="display: flex; flex-wrap: wrap;">
       <div class="col-md-12 columnBlockLayout" style="padding: 16px; margin: 60px 0px; min-height: 200px;">
          <!-- Sample code for Web API demonstration -->
          <style>
          #processingMsg {
             padding: 6px 12px;
             background: #eee;
             border-radius: 4px;
             position: fixed;
             top: 10px;
             left: 50%;
             transform: translateX(-50%);
             display: none;
             z-index: 9999;
             text-align: center;
             font-weight: bold;
          }
    
          table {
             border-collapse: collapse;
             width: 100%;
             margin-top: 10px;
             font-family: Arial, sans-serif;
          }
    
          th,
          td {
             border: 1px solid #ccc;
             padding: 6px;
             text-align: left;
          }
    
          button {
             cursor: pointer;
             border: 1px solid #aaa;
             padding: 4px 8px;
             border-radius: 4px;
             background: #fff;
             font-size: 14px;
             margin-right: 2px;
          }
    
          button.add {
             color: green;
          }
    
          button.save {
             color: green;
          }
    
          button.cancel {
             color: orange;
          }
    
          button.delete {
             color: red;
          }
    
          input {
             width: 95%;
             box-sizing: border-box;
          }
    
          td.actions {
             white-space: nowrap;
          }
    
          td[data-attribute="UserName"] {
             background: #f9f9f9;
             cursor: default;
          }
          </style>
    
          <div id="processingMsg">Processing...</div>
          <div id="dataTable"></div>
    
          <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
          <script>
          $(function () {
    
             // Safe WebAPI wrapper for Power Pages
             (function (webapi, $) {
                function safeAjax(opts) {
                var d = $.Deferred();
                shell.getTokenDeferred().done(function (token) {
                   opts.headers = opts.headers || {};
                   opts.headers["__RequestVerificationToken"] = token;
                   $.ajax(opts)
                      .done((data, ts, jq) => validateLoginSession(data, ts, jq, d.resolve))
                      .fail(d.reject);
                }).fail(() => d.rejectWith(this, arguments));
                return d.promise();
                }
                webapi.safeAjax = safeAjax;
             })(window.webapi = window.webapi || {}, jQuery);
    
             // Notification overlay
             const notify = (() => {
                const $m = $('#processingMsg'); let s = 0, t;
                return {
                show: (msg = 'Processing...') => { $m.text(msg); if (!s) $m.show(); s++; },
                hide: () => { s = Math.max(0, s - 1); if (!s) t = setTimeout(() => $m.hide(), 200); }
                };
             })();
    
             function ajaxCall(msg, opts) {
                notify.show(msg);
                return webapi.safeAjax(opts)
                .fail(r => alert(r.responseJSON?.error?.message || 'Server error'))
                .always(notify.hide);
             }
    
             // Table columns
             const cols = [
                { name: 'UserName', label: 'User Name', editable: false },
                { name: 'FirstName', label: 'First Name' },
                { name: 'LastName', label: 'Last Name' },
                { name: 'MiddleName', label: 'Middle Name' },
                { name: 'Age', label: 'Age' }
             ];
    
             let data = [];
             let serviceSession = '';
             function render() {
                const html = `<table>
                <thead>
                   <tr>
                      ${cols.map(c => `<th>${c.label}</th>`).join('')}
                      <th>Actions <button class="add">➕</button></th>
                   </tr>
                </thead>
                <tbody>
                   ${data.map(r => `<tr data-UserName="${r.UserName}">
                      ${cols.map(c => `<td data-attribute="${c.name}" data-value="${r[c.name] || ''}">
                            ${r[c.name] || ''}
                      </td>`).join('')}
                      <td class="actions">
                            <button class="delete">🗑️</button>
                      </td>
                   </tr>`).join('')}
                </tbody>
          </table>`;
                $('#dataTable').html(html);
             }
    
             // Double click row to edit except username
             $('#dataTable').on('dblclick', 'tr', function () {
                const $tr = $(this);
                if ($tr.hasClass('editing')) return;
                $tr.addClass('editing');
                $tr.find('td[data-attribute]').each(function () {
                const $td = $(this);
                if ($td.data('attribute') === 'UserName') return;
                const old = $td.text().trim();
                $td.html(`<input type="text" value="${old}" data-attr="${$td.data('attribute')}"/>`);
                });
                $tr.find('.actions').append('<button class="save">✅</button><button class="cancel">❌</button>');
             });
    
             $('#dataTable').on('click', '.save', function () {
                const $tr = $(this).closest('tr');
                const username = $tr.data('username');
                const updates = {};
                $tr.find('input').each(function () {
                const attr = $(this).data('attr');
                let value = $(this).val().trim();
    
                if (attr === 'Age') {
                   value = Number(value);
                   if (isNaN(value)) value = null; // safety fallback
                }
    
                updates[attr] = value;
                });
    
                ajaxCall('Updating...', {
                type: 'PUT',
                url: `/_api/serverlogics/services.odata.org`,
                contentType: 'application/json',
                data: JSON.stringify(Object.assign({ UserName: username, serviceSession: `${serviceSession}` }, updates)),
                success: () => { Object.assign(data.find(x => x.UserName === username), updates); render(); }
                });
             });
    
             $('#dataTable').on('click', '.cancel', () => render());
    
             $('#dataTable').on('click', '.delete', function () {
                const username = $(this).closest('tr').data('username');
                if (!confirm('Delete ' + username + '?')) return;
                ajaxCall('Deleting...', {
                type: 'DELETE',
                url: `/_api/serverlogics/services.odata.org?username=${username}&serviceSession=${serviceSession}`,
                success: () => { data = data.filter(x => x.UserName !== username); render(); }
                });
             });
    
             $('#dataTable').on('click', '.add', function () {
                const r = {
                serviceSession: `${serviceSession}`,
                UserName: 'user' + Math.floor(Math.random() * 9000 + 1000),
                FirstName: 'New',
                LastName: 'Person',
                MiddleName: '',
                Age: 25
                };
                ajaxCall('Adding...', {
                type: 'POST',
                url: `/_api/serverlogics/services.odata.org`,
                contentType: 'application/json',
                data: JSON.stringify(r),
                success: () => { data.unshift(r); render(); }
                });
             });
    
             // Initial load
             ajaxCall('Loading...', {
                type: 'GET',
                url: `/_api/serverlogics/services.odata.org`,
                contentType: 'application/json'
             }).done(resp => {
                const parsed = JSON.parse(resp.data);
                const body = JSON.parse(parsed.Body);
    
                const ctx = body['@odata.context'];
                const match = ctx.match(/\\S\\[^)]*\\/);
                serviceSession = match ? match[0] : '';
    
                data = (body.value || []).map(r => ({
                UserName: r.UserName,
                FirstName: r.FirstName,
                LastName: r.LastName,
                MiddleName: r.MiddleName,
                Age: r.Age
                }));
                render();
             });
    
          });
          </script>
       </div>
    </div>
    </div>
    
  8. Įrašyti failą

    Pastaba.

    Šis kodas sukuria interaktyvią duomenų lentelės sąsają, skirtą CRUD (kurti, skaityti, atnaujinti, naikinti) operacijoms demonstruoti su išorine OData paslauga naudojant Power Pages serverio logiką. Jame yra CSS stilius, skirtas interaktyviam lentelės išdėstymui, apdorojimo pranešimų perdanga ir "JavaScript" funkcija, leidžianti vartotojams peržiūrėti duomenis, gautus iš išorinės tarnybos, pridėti naujų įrašų spustelėjus ➕ mygtuką, redaguoti esamus įrašus dukart spustelėjus lentelės eilutes (išskyrus lauką Vartotojo vardas), įrašyti pakeitimus naudojant ✅, atšaukti redagavimą naudojant ❌ir naikinti įrašus naudojant 🗑mygtuką ️. Kodas naudoja jQuery ir saugų WebAPI apvalkalą, kad atliktų autentifikuotus AJAX iškvietimus į /_api/serverlogics/services.odata.org galinį tašką, apdorodamas atsakymo duomenis, kad išanalizuotų OData kontekstą ir valdytų aptarnavimo seansą tolesnėms operacijoms.

  9. Grįžkite į "Power pages" dizaino įrankį.

  10. Dialogo lange Redaguojate kodą "Visual Studio Code", skirtame žiniatinkliui , vykdykite instrukcijas ir spustelėkite mygtuką Sinchronizuoti .

3 veiksmas: serverio logikos naudojimas skaitymui, peržiūrai, redagavimui, kūrimui ir naikinimui

Norėdami patikrinti serverio logikos funkcionalumą:

  1. Pasirinkite Peržiūra, tada pasirinkite Darbalaukis.
  2. Prisijunkite prie svetainės naudodami vartotojo abonementą, kuriam priskirtas anksčiau sukurtas serverio logikos vartotojo vaidmuo. Kadangi ankstesniame veiksme pasirinkome administratorių vaidmenį, šiame pavyzdyje prisijunkite kaip administratorius.
  3. Eikite į anksčiau sukurtą serverio logikos tinklalapį.
  4. Patikrinkite operacijas.

Serverio logikos apžvalga
Autoriaus serverio logika
Serverio objektaiKaip sąveikauti su "Dataverse" lentelėmis naudojant serverio logiką