วิธีการ: โต้ตอบกับบริการภายนอกโดยใช้ตรรกะของเซิร์ฟเวอร์

ในคู่มือนี้ คุณจะตั้งค่าเว็บเพจที่จะใช้ตรรกะเซิร์ฟเวอร์ในการอ่าน เขียน อัปเดต และลบระเบียนจากวัตถุเซิร์ฟเวอร์ httpclient ของบริการภายนอก

Note

ตัวอย่างนี้ใช้ https://services.odata.org/TripPinRESTierService แต่คุณสามารถใช้เครื่องมือทดสอบฟรีอื่นๆ ที่พร้อมใช้งานแบบสาธารณะได้

ขั้นตอนที่ 1: สร้างตรรกะเซิร์ฟเวอร์

  1. ลงชื่อเข้าใช้ Power Pages

  2. เลือกไซต์ + แก้ไข

  3. นําทางไปยัง ตั้งค่า พื้นที่ทํางาน จากนั้นเลือก ตรรกะเซิร์ฟเวอร์ (ตัวอย่าง)

    สกรีนช็อตแสดงตําแหน่งที่จะเลือกตรรกะของเซิร์ฟเวอร์ในการตั้งค่าพื้นที่ทํางาน

  4. เลือก +ตรรกะเซิร์ฟเวอร์ใหม่

  5. ป้อนชื่อสําหรับตรรกะของเซิร์ฟเวอร์ ชื่อนี้ถูกใช้ใน API เป็นตัวระบุทรัพยากรขณะสร้าง API ตรรกะของเซิร์ฟเวอร์ เช่น:

    ทรัพย์สิน ค่าตัวอย่าง
    ชื่อ services.odata.org
    ชื่อที่ใช้แสดง Performing CRUD operations using OData service
  6. เลือก +เพิ่มบทบาท เพื่อกําหนดบทบาทของเว็บที่เหมาะสม เพิ่มบทบาทผู้ดูแลระบบในตรรกะเซิร์ฟเวอร์ ในตัวอย่างนี้ เลือก ผู้ดูแลระบบ และลงชื่อเข้าใช้ในฐานะผู้ดูแลระบบเพื่อดําเนินการต่อ

  7. เลือก เพิ่ม

  8. เลือกตรรกะเซิร์ฟเวอร์และเลือก แก้ไขโค้ด

    เลือกแก้ไขรหัส

  9. ใน การแก้ไขใน Microsoft Visual Studio Code สําหรับกล่องโต้ตอบเว็บ เลือก เปิดรหัส Visual Studio เพื่อเขียนตรรกะแบบกําหนดเอง

    คุณจะพบวิธีการและสคริปต์ที่กําหนดไว้ล่วงหน้าในไฟล์

  10. กําหนดวิธีการตรรกะของเซิร์ฟเวอร์เพื่ออ่าน แก้ไข สร้าง ลบการดําเนินการโดยใช้บริการภายนอก

    เพิ่มค่าคงที่ต่อไปนี้ baseUrl ก่อน get() วิธีการ

    
     const baseUrl  = "https://services.odata.org/TripPinRESTierService";
    
    
  11. แทนที่ getฟังก์ชัน , post, putและ del ตัวอย่าง ด้วยรหัสต่อไปนี้

    
    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. บันทึกไฟล์

    เคล็ดลับ

    ใช้ Ctrl+S เพื่อบันทึก

ขั้นตอนที่ 2: สร้างเว็บเพจ

  1. เปิดใช้สตูดิโอออกแบบ Power Pages

  2. ในพื้นที่ทํางานของหน้า ให้เลือก+ หน้า

    เพิ่มหน้าใหม่

  3. ในกล่องโต้ตอบ อธิบายหน้าเพื่อสร้าง ให้เลือก วิธีอื่นๆ เพื่อเพิ่มหน้า

  4. ในกล่องโต้ตอบ เพิ่มหน้า ให้ป้อนรายละเอียด

    1. ในกล่อง ชื่อ ให้ใส่ ตรรกะของเซิร์ฟเวอร์ และเลือก เริ่มต้นจากเค้าโครงว่างเปล่า
    2. เลือก เพิ่ม

    ป้อนค่าเพื่อเพิ่มหน้า

  5. เลือกตัวเลือก แก้ไขรหัส ที่มุมขวาบน

  6. ในแก้ไขใน Visual Studio Code สําหรับกล่องโต้ตอบเว็บ เลือกเปิดรหัส Visual Studio

  7. แทนที่โค้ดที่พบในหน้า HTML ด้วยข้อมูลต่อไปนี้:

    <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. บันทึกไฟล์

    Note

    โค้ดนี้สร้างอินเทอร์เฟสตารางข้อมูลแบบโต้ตอบเพื่อสาธิตการดําเนินการ CRUD (สร้าง อ่าน อัปเดต ลบ) ด้วยบริการ OData ภายนอกโดยใช้ตรรกะของเซิร์ฟเวอร์ Power Pages ซึ่งรวมถึงการกำหนดลักษณะ CSS สำหรับการแสดงผลตารางแบบตอบสนอง การแจ้งเตือนที่กำลังดำเนินการแบบซ้อน และการทำงานของ JavaScript ที่ช่วยให้ผู้ใช้สามารถดูข้อมูลที่ได้จากบริการภายนอก เพิ่มระเบียนใหม่โดยการคลิกปุ่ม ➕ แก้ไขระเบียนที่มีอยู่โดยคลิกสองทีบนแถวของตาราง (ยกเว้นเขตข้อมูล UserName) บันทึกการเปลี่ยนแปลงด้วย ✅ ยกเลิกการแก้ไขด้วย ❌ และลบระเบียนโดยใช้ปุ่ม 🗑️ รหัสนี้ใช้ jQuery และตัวคลุม WebAPI ที่ปลอดภัยเพื่อเรียก AJAX ที่ได้รับการรับรองความถูกต้องไปยัง /_api/serverlogics/services.odata.org endpoint จัดการข้อมูลการตอบสนองเพื่อแยกวิเคราะห์บริบท OData และจัดการเซสชันบริการสําหรับการดําเนินการที่ตามมา

  9. กลับไปยังตัวออกแบบ Power Pages

  10. ในคุณกําลังแก้ไขรหัสใน Visual Studio Code สําหรับกล่องโต้ตอบเว็บ ให้ทําตามคําแนะนําและคลิกปุ่ม ซิงค์

ขั้นตอนที่ 3: ใช้ตรรกะเซิร์ฟเวอร์เพื่ออ่าน ดู แก้ไข สร้าง และลบ

เมื่อต้องการทดสอบฟังก์ชันตรรกะของเซิร์ฟเวอร์:

  1. เลือกแสดงตัวอย่าง แล้วเลือกเดสก์ท็อป
  2. ลงชื่อเข้าใช้ไซต์ของคุณด้วยบัญชีผู้ใช้ที่ได้รับการกําหนดบทบาท ผู้ใช้เชิงตรรกะของเซิร์ฟเวอร์ ที่คุณสร้างไว้ก่อนหน้านี้ ขณะที่เราเลือกบทบาท ผู้ดูแลระบบ ในขั้นตอนก่อนหน้า ในตัวอย่างนี้ ให้ลงชื่อเข้าใช้ในฐานะผู้ดูแลระบบ
  3. ไปยังเว็บเพจ ตรรกะของเซิร์ฟเวอร์ ที่สร้างไว้ก่อนหน้านี้
  4. ตรวจสอบการดําเนินการ

ภาพรวมตรรกะของเซิร์ฟเวอร์
ตรรกะของเซิร์ฟเวอร์ผู้เขียน
วัตถุเซิร์ฟเวอร์วิธีการโต้ตอบกับตาราง Dataverse โดยใช้ตรรกะของเซิร์ฟเวอร์