Category: Developer

งานพัฒนาระบบ, เขียนโปรแกรม

  • ทำอย่างไรให้เว็บไซต์ที่เราพัฒนาสามารถอัพโหลดไฟล์แบบคราวละหลายไฟล์ได้โดยไม่จำกัดจำนวน ด้วย ASP.NET(C#)

              ในการพัฒนาเว็บไซต์ บางครั้งอาจมีความจำเป็น หรือความต้องการจากผู้ใช้ที่ต้องการให้เว็บไซต์ดังกล่าวมีฟังก์ชั่นการทำงานในส่วนของการอัพโหลดไฟล์เพื่อแนบไฟล์เข้าไปในระบบและบันทึกลงฐานข้อมูล เพื่อให้สามารถเรียกดูข้อมูลการแนบไฟล์ดังกล่าวได้ในภายหลัง การอัพโหลดไฟล์จึงถือเป็นอีกหนึ่งฟังก์ชั่นการทำงานที่นักพัฒนาเว็บไซต์ควรทราบไว้ ซึ่งลักษณะการทำงานโดยทั่วไปส่วนใหญ่เราจะใช้ Control ที่มีเรียกว่า “FileUpload” แบบอัพโหลดครั้งละ 1 ไฟล์ และหากมีมากกว่านั้นก็จะมีการสร้างตัว FileUpload มาวางไว้ในหน้าจอเพิ่มตามจำนวนที่ต้องการแบบตายตัว เช่น หากในหน้าจอดังกล่าวต้องการสามารถให้ทำการอัพโหลดไฟล์ได้ไม่เกิน 5 ไฟล์ต่อการอัพโหลดแต่ละครั้งก็จะมีการลากคอนโทรล FileUpload มาวางไว้ในหน้าจอจำนวน 5 ตัว เพื่อให้สามารถรองรับความต้องการในการอัพโหลดไฟล์ของผู้ใช้ได้ แต่ผู้เขียนพบว่าการทำงานดังกล่าวอาจไม่รองรับความต้องการในการทำงานของผู้ใช้ที่จะเพิ่มไฟล์ได้ครั้งละหลายๆไฟล์โดยไม่จำกัดและผู้พัฒนาไม่จำเป็นต้องระบุหรือสร้างคอนโทรล FileUpload มาวางในหน้าจอในจำนวนที่ตายตัวโดยไม่จำเป็น โดยผู้ใช้สามารถคลิกปุ่มเพื่อเพิ่มจำนวนในการอัพโหลดไฟล์แต่ละครั้งได้เองเพื่อความยืดหยุ่นในการใช้งาน ในบทความนี้ ผู้เขียนจึงขอเสนอแนวทางในการพัฒนาเว็บไซต์โดยใช้ ASP.NET(C#) ในแบบที่มีการอัพโหลดไฟล์ได้คราวละหลายๆไฟล์ในแบบไม่ต้องจำกัดจำนวนคอนโทรล FileUpload ในหน้าจอโดยมีการระบุจำนวนไฟล์ที่สามารถอัพโหลดได้ในแต่ละครั้งโดยผู้พัฒนาแบบตายตัวอย่างเช่นที่กล่าวไว้ข้างต้น

              หลังจากที่ได้มีการศึกษาเพิ่มเติม ผู้เขียนพบว่าใน .NET Framework เวอร์ชั่น 4.5 นั้นจะมีการเพิ่ม Feature การทำงานในส่วนนี้ให้กับคอนโทรล FileUpload ไว้แล้วผ่าน Properties ที่เรียกว่า AllowMultiple ซึ่งจะทำให้สะดวกต่อการพัฒนาและสามารถลดปัญหาดังกล่าวข้างต้นได้ แต่สำหรับเวอร์ชั่นที่ต่ำกว่ายังคงต้องมีการปรับปรุงพัฒนาเพิ่มเติมเอง ในบทความนี้จึงขอยกตัวอย่างการพัฒนาทั้ง 2 แบบในเบื้องต้นโดยจะเน้นไปในแบบเวอร์ชั่นที่ต่ำกว่า 4.5 เพื่อให้ผู้อ่านได้นำไปเป็นแนวทางในการพัฒนาต่อไป ดังนี้
    1. การอัพโหลดไฟล์คราวละหลายๆไฟล์โดยใช้ .Net Framework เวอร์ชั่นที่ต่ำกว่า 4.5

              ในบทความนี้ ผู้เขียนขอเสนอแนวทางแบบที่เป็นการพัฒนาโดยใช้จาวาสคริปต์เข้ามาเป็นตัวช่วยให้สามารถอัพโหลดไฟล์ได้ครั้งละหลายไฟล์ต่อการอัพโหลดแต่ละครั้ง เพื่อลดจำนวนการโหลดของหน้าจอและทำให้ผู้ใช้รู้สึกว่าการทำงานดังกล่าวเป็นไปด้วยความรวดเร็วไม่ต้องใช้เวลานาน โดยจะอธิบายทีละขั้นตอน ดังนี้

    1) ออกแบบหน้าจอการทำงานในฝั่ง Client  ทำการออกแบบหน้าจอการทำงานไว้ในเบื้องต้น โดยมีการสร้างคอนโทรล FileUpload มาตั้งต้นไว้ 1 ตัว และมีปุ่มเพื่อให้ทำการเพิ่มคอนโทรล FileUpload ได้เองอัตโนมัติโดยตัวผู้ใช้เอง และปุ่มที่ใช้ในการอัพโหลดไฟล์จากคอนโทรล FileUpload ทั้งหมด ดังนี้

    <body>
    <form id="form1" runat="server">
    <div>
     <div id="fileUploadarea" class="Divborder">
      <div id='divfirstUpload'><br /><asp:FileUpload ID="fuMultiple" runat="server" CssClass="fileUpload" onchange="javascipt:FileValidate(this,5);" />&nbsp;  <input style="display:inline;" id="BtnRemove" type="button" value="Remove" onclick="DelFileUpload('divfirstUpload');" /> 
    </div> 
    </div>
    <br /> 
    <div>&nbsp; 
    <input style="display:inline; background-color: #A4EDFF; color: #333333; width: 150px; font-weight: bold;" id="btnAddMoreFiles" type="button" value="Add more files" onclick="AddMoreFilesWithMax(6);" />
    &nbsp; <asp:Button ID="BtnUpload" runat="server" onclick="BtnUpload_Click" Text="Upload" OnClientClick="return ValidateFileUpload();" BackColor="#3399FF" Font-Bold="True" ForeColor="White" Width="150px" /> 
    <br> 
    <asp:GridView ID="gvResult" runat="server" AutoGenerateColumns="False" CellPadding="4" ForeColor="#333333" GridLines="None" Width="410px">
    <RowStyle BackColor="#EFF3FB" /> 
    <Columns> 
    <asp:BoundField DataField="Name" HeaderText="ชื่อไฟล์"> 
    <ItemStyle Width="200px" /> </asp:BoundField> 
    <asp:BoundField DataField="FileSize" HeaderText="ขนาดไฟล์(KB)"> 
    <ItemStyle HorizontalAlign="Right" Width="120px" /> 
    </asp:BoundField> 
    </Columns> 
    <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> 
    <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" /> <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" /> <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> 
    <EditRowStyle BackColor="#2461BF" /> <AlternatingRowStyle BackColor="White" /> 
    </asp:GridView> 
    </div> 
    </div> 
    </form> 
    </body>

    2) ในส่วนของจาวาสคริปต์ที่ใช้เป็นตัวช่วยในการตรวจสอบ โดยจะแยกเป็นแต่ละ function ดังนี้

    2.1) ฟังก์ชั่นที่ใช้ในการเพิ่มไฟล์ได้ไม่จำกัด โดยใช้ชื่อว่า AddMoreFiles()

    <script language="javascript" type="text/javascript">
    
    function AddMoreFiles() {
    
      if (!document.getElementById && !document.createElement)
        return false;
    ////อ้างอิงถึง div ที่มีชื่อว่าfileUploadarea
      var fileUploadarea = document.getElementById("fileUploadarea"); 
      if (!fileUploadarea) return false; 
       var newLine = document.createElement("br"); fileUploadarea.appendChild(newLine); 
       var newFile = document.createElement("input"); 
       newFile.type = "file"; newFile.setAttribute("class", "fileUpload");
    
    /////กำหนดค่าเริ่มต้นให้กับตัวแปร AddMoreFiles.lastAssignedId 
    เพื่อใช้ในการกำหนด ID ให้กับคอนโทรลที่สร้างขึ้น และเป็นตัวนับ
      if (!AddMoreFiles.lastAssignedId) 
        AddMoreFiles.lastAssignedId = 1;
    
     //////กำหนดค่าแอททริบิวต์ต่างๆให้กับ FileUpload ที่ทำการสร้างใหม่ ในทีนี้คือ id และ name
        newFile.setAttribute("id", "FileUpload" + AddMoreFiles.lastAssignedId);  
        newFile.setAttribute("name", "FileUpload" + AddMoreFiles.lastAssignedId); 
    
     //////สร้าง div ขึ้นมาใหม่ และกำหนดค่าแอททริบิวต์ต่างๆให้กับ div ที่ทำการสร้างใหม่ 
    ในทีนี้คือ id และ เพิ่มคอนโทรลที่สร้าง tag ไว้ด้านบนเข้ามาไว้ใน div 
        var div = document.createElement("div"); 
        div.appendChild(newFile); 
        div.setAttribute("id", "div" + AddMoreFiles.lastAssignedId); 
    
    //////เพิ่ม div ที่สร้างใหม่ไปยัง div ที่มีชื่อว่า fileUploadarea และเพิ่มค่าของตัวแปร AddMoreFiles.lastAssignedId   
        fileUploadarea.appendChild(div); 
        AddMoreFiles.lastAssignedId++; 
    }

    2.2) ฟังก์ชั่นที่ใช้ในการเพิ่มไฟล์ได้โดยมีการระบุจำนวนสูงสุดที่ยอมให้อัพโหลดแต่ละครั้ง ในกรณีที่ต้องการระบุค่าจำนวนไฟล์ที่ต้องการให้ผู้ใช้สามารถอัพโหลดได้สูงสุดในแต่ละครั้ง สามารถปรับแก้เพิ่มเติมจากฟังก์ชั่นก่อนหน้านี้ โดยการส่งพารามิเตอร์จำนวนมากสุดที่ยอมให้สร้างตัวอัพโหลดไฟล์ได้ โดยใช้ชื่อฟังก์ชั่นว่า AddMoreFilesWithMax(x) ดังนี้

    function AddMoreFilesWithMax(x) 
    { //////กำหนดค่าให้กับ AddMoreFiles.lastAssignedId 
    เพื่อเป็นค่าตั้งต้นในการไปเซทค่า id และ name ของคอนโทรลที่สร้างใหม่ 
    โดยในที่นี้เริ่มต้นที่ 2 เนื่องจากเดิมมีคอนโทรลอัพโหลดไฟล์อยู่เดิมแล้ว 1 ตัว
      if (!AddMoreFiles.lastAssignedId)
          AddMoreFiles.lastAssignedId = 2;
    
       if (!document.getElementById && !document.createElement)
          return false; 
      var fileUploadarea = document.getElementById("fileUploadarea");
        if (!fileUploadarea) return false;
    
    /////เป็นการตรวจสอบเงื่อนไขว่ายังไม่เกินจำนวนมากสุดที่ระบุไว้ผ่านพารามิเตอร์ x
          if (AddMoreFiles.lastAssignedId <= x) 
          { 
          var newLine = document.createElement("br"); 
    
          //สร้างปุ่ม Remove เพื่อใช้ลบคอนโทรล FileUpload ที่สร้างขึ้นออกโดยผู้ใช้ 
          var newbtnDel = document.createElement("input"); 
          newbtnDel.setAttribute("id", "btnDelUpload" + AddMoreFiles.lastAssignedId);
          newbtnDel.setAttribute("name", "btnDelUpload" + AddMoreFiles.lastAssignedId); 
          newbtnDel.setAttribute("value", "Remove");   
          newbtnDel.type = "button"; 
    
         //////สร้างคอนโทรล FileUpload ขึ้นใหม่และกำหนดแอททริบิวต์ต่างๆให้
          var newFile = document.createElement("input"); 
          newFile.type = "file"; 
          newFile.setAttribute("class", "fileUpload");
          newFile.setAttribute("id", "FileUpload" + AddMoreFiles.lastAssignedId); 
          newFile.setAttribute("name", "FileUpload" + AddMoreFiles.lastAssignedId);
    
    //////เป็นส่วนของการเรียกฟังก์ชั่นในการตรวจสอบไฟล์ที่ทำการอัพโหลดว่าถูกต้องตรงตามเงื่อนไขหรือไม่
         เมื่อมีการเลือกไฟล์ใดๆจากผู้ใช้ ซึ่งจะพูดถึงในส่วนถัดไปในการสร้างฟังก์ชั่น FileValidate(ctrl,maxVal) 
          newFile.setAttribute('onchange', 'javascipt:FileValidate(this,5);');
    
    //////สร้าง div ขึ้นมาใหม่ และกำหนดค่าแอททริบิวต์ต่างๆให้กับ div ที่ทำการสร้างใหม่ 
    ในทีนี้คือ id และ เพิ่มคอนโทรลที่สร้าง tag ไว้ด้านบนเข้ามาไว้ใน div 
          var div = document.createElement("div");
          div.appendChild(newLine);
          div.appendChild(newFile);
    //////เพิ่มช่องว่างระหว่างคอนโทรลอัพโหลดไฟล์และปุ่ม Remove เพื่อความสวยงาม
          div.appendChild(document.createTextNode('\u00A0'));
          div.appendChild( newbtnDel);
          div.setAttribute("id", "div" + AddMoreFiles.lastAssignedId);
    
    //////เพิ่ม event การคลิกปุ่ม Remove เพื่อให้ไปเรียกใช้ฟังก์ชั่น DelFileUpload
    โดยส่งค่า id ของ div ที่ต้องการให้ลบออกซึ่งจะกล่าวถึงในส่วนถัดไปของการสร้างฟังก์ชั่น DelFileUpload(divid);
          newbtnDel.setAttribute('onclick', 'javascipt:DelFileUpload(\'' + "div" + AddMoreFiles.lastAssignedId + '\');');
    
          fileUploadarea.appendChild(div);
          AddMoreFiles.lastAssignedId++; } 
    
    ///////กรณีที่มีจำนวนตัวอัพโฟลดไฟล์ที่ถูกสร้างขึ้นเองเกินกว่าที่กำหนด(ค่าพารามิเตอร์ x) 
    จะแสดงข้อความให้ทราบ
     else { 
           alert("ขออภัย ท่านสามารถอัพโหลดไฟล์ได้สูงสุดครั้งละไม่เกิน " + x + " ไฟล์ต่อการอัพโหลดแต่ละครั้ง กรุณาลองใหม่อีกครั้ง"); 
          return false;
           } 
          }

    2.3) ฟังก์ชั่นที่ใช้ในการตรวจสอบขนาดของไฟล์ โดยมีการระบุขนาดสูงสุดที่ยอมให้อัพโหลดแต่ละครั้ง โดยใช้ชื่อฟังก์ชั่นว่า FileValidate(ctrlFile,MaxSize)

    ////เป็นการประกาศตัวแปรที่ใช้ในการตรวจสอบชนิดของไฟล์ที่ยอมให้อัพโหลดได้
    var _validFileExtensions = [".jpg", ".jpeg", ".bmp", ".gif", ".png", ".pdf"];
    function FileValidate(ctrlFile,MaxSize) 
    {//////พารามิเตอร์ที่รับเข้ามาคือตัวคอนโทรลของการอัพโหลดไฟล์ที่ต้องการตรวจสอบ(ctrlFile) 
    และขนาดสูงสุดของไฟล์ที่ยอมให้อัพโหลดในแต่ละคอนโทรล(MaxSize)
    
    ////ดึงค่าชื่อของไฟล์ที่อัพโหลดที่ต้องการตรวจสอบ
      var sFileName = ctrlFile.value;
    
    /////ตรวจสอบเมื่อพบชื่อไฟล์ที่ดึง
       if (sFileName.length > 0) 
       { 
         var blnValid = false; 
    //////////ตรวจสอบนามสกุลของไฟล์ที่ดึงมาจากชื่อไฟล์กับค่าของนามสกุลไฟล์ที่ยอมให้อัพโหลด
    จากตัวแปร _validFileExtensions
         for (var j = 0; j < _validFileExtensions.length; j++) 
          { var sCurExtension = _validFileExtensions[j]; 
           if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) 
           { 
             blnValid = true; 
             break; 
            } 
          }   
    //////กรณีไฟล์ดังกล่าวมีนามสกุลที่แตกต่างจากที่กำหนดจะแสดงข้อความแจ้งเตือน 
    และล้างค่าของชื่อไฟล์ในคอนโทรลอัพโหลดไฟล์ตัวดังกล่าว
         if (!blnValid) 
         { alert("ไม่สามารถอัพโหลดไฟล์ดังกล่าวได้ เนื่องจากรองรับเฉพาะไฟล์ที่มีนามสกุลดังนี้เท่านั้น: " + _validFileExtensions.join(", ")); 
          ctrlFile.value = ""; 
          return false; 
         } 
         else 
         {
    /////หากไฟล์ที่อัพโหลดมีนามสกุลไฟล์ตามที่ระบุ จะทำการตรวจสอบขนาดของไฟล์ว่าไม่เกินจากขนาดสูงสุด
    ที่กำหนดหรือไม่ โดยมีการคำนวณหน่วยเป็น MB
           var fileSize = parseFloat(ctrlFile.files[0].size / 1048576).toFixed(2);
    
    /////หากขนาดของไฟล์เกินกว่าที่กำหนดจะแสดงข้อความแจ้งเตือน และล้างค่าไฟล์ที่ต้องการอัพโหลด
    ในคอนโทรลอัพโหลดไฟล์ดังกล่าว
           if (fileSize > MaxSize) 
            { alert(" ขออภัย ขนาดของไฟล์ที่ต้องการอัพโหลดมีขนาดใหญ่เกินกว่าทีกำหนด(" + MaxSize + " MB)"); 
              ctrlFile.value = ""; 
              return false;   
           } 
         }   
        }   
      return true; 
      }

    2.4) ฟังก์ชั่นที่ใช้ในการตรวจสอบว่ามีการเลือกไฟล์ที่ต้องการอัพโหลดแล้วหรือไม่ เมื่อมีการกดปุ่ม “Upload” โดยใช้ชื่อฟังก์ชั่นว่า ValidateFileUpload() 

    function ValidateFileUpload() { 
    //////เป็นการค้นหาคอนโทรลไฟล์อัพโหลดที่มีในหน้าจอโดยใช้ tag input 
    และตรวจสอบที่มี type เป็น "file" ใส่ไว้ในตัวแปร arrInputs
        var arrInputs = document.getElementsByTagName("input");
        var blnValid; 
        var oInput;
        for (var i = 0; i < arrInputs.length; i++)
         { oInput = arrInputs[i]; 
          if (oInput.type == "file") 
          { 
           var sFileName = oInput.value; 
    
     ///////หากพบตัวอัพโหลดไฟล์ตัวใดที่ยังไม่ได้ทำการเลือกไฟล์ไว้ จะทำการแสดงข้อความแจ้งเตือนให้ทราบ
           if (sFileName.length == 0) 
             { blnValid = false; 
              alert("ขออภัย ไม่สามารถอัพโหลดไฟล์ได้ เนื่องจากพบว่ามีบางไฟล์ไม่ได้ถูกเลือก กรุณาลองใหม่อีกครั้ง"); 
              return false;   
             } 
          }   
         }   
    return true; 
    }

    2.5) ฟังก์ชั่นที่ใช้ในการลบคอนโทรลที่ใช้ในการอัพโหลดไฟล์ โดยใช้ชื่อฟังก์ชั่นว่า DelFileUpload(dv) ซึ่งจะส่งพารามิเตอร์เป็น id ของ div ตัวที่ต้องการให้ลบ และถูกเรียกใช้เมื่อมีการกดปุ่ม “Remove”

    function DelFileUpload(dv) 
    { ////ค้นหา div ตาม id ที่ส่งเข้ามา
       var elem = document.getElementById(dv); 
      ///ทำการลบ div นั้นออกจากหน้าจอและลดค่าของ AddMoreFiles.lastAssignedId ลง 1
    เพื่อใช้ในการคำนวณค่าสูงสุดและกำหนด tag ของ id และ name ของคอนโทรลที่สร้างใหม่ต่อไป
       elem.parentNode.removeChild(elem); 
       AddMoreFiles.lastAssignedId = AddMoreFiles.lastAssignedId - 1; 
    }

    3) ในฝั่งเซฺิร์ฟเวอร์ (C#)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    /////เป็น namespace ที่ต้องอ้างอิงเพิ่มเพื่อใช้ในการจัดการข้อมูลกับ datatable
    using System.Data;
    /////เป็น namespace ที่ต้องอ้างอิงเพิ่มเพื่อใช้ในการจัดการเกี่ยวกับการอัพโหลดไฟล์
    using System.IO;
    public partial class MultipleUpload : System.Web.UI.Page
    {
    protected void BtnUpload_Click(object sender, EventArgs e)
    {
      try
      {
    
     //////สมมุติเพื่อนำไปประยุกต์ใช้กับการบันทึกลงฐานข้อมูลต่อไป 
    โดยสร้างโครงสร้าง datatable ที่ชื่อว่า dtFiles 
         DataTable dtFiles = new DataTable();
         dtFiles.Columns.AddRange(new DataColumn[3] { new DataColumn("Id", typeof(int)),
         new DataColumn("Name", typeof(string)),
         new DataColumn("FileSize",typeof(string)) });
    
    ////เป็นการดึงคอนโทรลในการอัพโหลดไฟล์ที่ถูกสร้างขึ้นและวนรอบในการบันทึกไฟล์ดังกล่าว
     HttpFileCollection hfc = Request.Files;
     for (int i = 0; i < hfc.Count; i++)
     {
        HttpPostedFile hpf = hfc[i];
       if (hpf.ContentLength > 0)
        {
    //////บันทึกไฟล์ตามที่ระบุไว้
        hpf.SaveAs(Server.MapPath("~/uploads/") + System.IO.Path.GetFileName(hpf.FileName));
    
    ////เพิ่มข้อมูลลงไปใน datatable ที่สร้างไว้ สำหรับการใช้งานจริงอาจเป็นการติดต่อเพื่อบันทึกลงฐานข้อมูล 
        dtFiles.Rows.Add(i,hpf.FileName, hpf.ContentLength / 1024);
         }
       }
     if (dtFiles.Rows.Count > 0) 
     {
    //////ดึงข้อมูลจาก datatable มาแสดงในกริดวิว
        gvResult.DataSource = dtFiles;
        gvResult.DataBind();
     
     }
       }
      }
      catch (Exception)
      {
       throw;
       }
      }
    }
    

    เพิ่มเติม :
    หากต้องการตกแต่งเพื่อความสวยงามสามารถใส่ StyleSheet เพิ่มเติมได้ ดังตัวอย่างต่อไปนี้

    <style type="text/css">
      .fileUpload
      {
       width:255px;
       font-size:11px;
       color:#000000;
       border:solid;
       border-width:1px;
       border-color:#7f9db9;
       height:17px;
      }
     .Divborder
      {
       border: 2px solid;
       border-radius: 5px;
       padding:10px;
       width:390px;
      }
    </style>
    

    ตัวอย่างผลลัพธ์ที่ได้

    1) แสดงหน้าจอ โดยแรกเริ่มมีอัพโหลดไฟล์ตั้งต้น 1 ตัว

    uploadsingle

    2) แสดงหน้าจอเมื่อมีการกดปุ่ม “Add more files” uploadmulti2

    3) แสดงผลลัพธ์หลังจากบันทึกข้อมูลเรียบร้อยแล้วmultipleResult2

    2. การอัพโหลดไฟล์คราวละหลายๆไฟล์โดยใช้ .Net Framework เวอร์ชั่น 4.5  ซึ่งในบทความนี้จะไม่ลงรายละเอียดมากนัก ผู้อ่านสามารถนำไปประยุกต์เพิ่มเติมได้ โดยจะอธิบายทีละขั้นตอนคร่าวๆ ดังนี้

    1) การออกแบบในหน้าจอฝั่ง Client

    <body>
    <form id="form1" runat="server">
    <div>
    <asp:FileUpload ID="file_upload" runat="server" AllowMultiple="true" />
    <asp:Button ID="btnFileUpload" runat="server" Text="Upload" OnClick="btnFileUpload_Click" />
    <asp:Label ID="lblUploadStatus" runat="server"></asp:Label><br />
     <asp:GridView ID="gvResult" runat="server" AutoGenerateColumns="False" CellPadding="4" ForeColor="#333333" GridLines="None" Width="410px">
     <AlternatingRowStyle BackColor="White" />
     <Columns>
     <asp:BoundField DataField="Name" HeaderText="ชื่อไฟล์">
     <ItemStyle Width="300px" />
     </asp:BoundField>
     <asp:BoundField DataField="filesize" HeaderText="ขนาดไฟล์(KB)">
     <ItemStyle HorizontalAlign="Right" Width="110px" />
     </asp:BoundField>
     </Columns>
     <EditRowStyle BackColor="#2461BF" />
     <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
     <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
     <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
     <RowStyle BackColor="#EFF3FB" />
     <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
     <SortedAscendingCellStyle BackColor="#F5F7FB" />
     <SortedAscendingHeaderStyle BackColor="#6D95E1" />
     <SortedDescendingCellStyle BackColor="#E9EBEF" />
     <SortedDescendingHeaderStyle BackColor="#4870BE" />
     </asp:GridView>
    </div>
    </form>
    </body>

    2) การพัฒนาในฝั่งเซิร์ฟเวอร์(C#)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.IO;
    using System.Data;
    namespace WebAppTest
    {
     public partial class MultipleUpload : System.Web.UI.Page
     {
     protected void btnFileUpload_Click(object sender, EventArgs e)
     {
     try
     {
    ///////การตรวจสอบขนาดไฟล์และไฟล์ต้องเป็นชนิด image/jpeg เท่านั้น
     if (file_upload.HasFile && file_upload.PostedFiles.All(x => x.ContentType == "image/jpeg" && x.ContentLength < 102400))
     {
    ///////ประกาศตัวแปร และกำหนดโครงสร้างของ datatable
     int i = 1;
     DataTable dtFiles = new DataTable();
     dtFiles.Columns.AddRange(new DataColumn[3] { new DataColumn("Id", typeof(int)),
     new DataColumn("Name", typeof(string)),
     new DataColumn("FileSize",typeof(string)) });
     foreach (var file in file_upload.PostedFiles)
     {
    //////บันทึกไฟล์ที่เลือก
       file_upload.SaveAs(Server.MapPath("~/Fileupload/") + Path.GetFileName(file.FileName));
    ////วนบันทึกข้อมูลไฟล์ที่อัพโหลดลงใน datatable  
        dtFiles.Rows.Add(i, file.FileName, file.ContentLength / 1024);
     }
    
    ////แสดงข้อความเมื่อการอัพโหลดเสร็จสมบูรณ์
       lblUploadStatus.Text = "บันทึกสำเร็จ";
    
    ////แสดงค่าที่ได้ลงในกริดวิว
     if (dtFiles.Rows.Count > 0)
     {
     gvResult.DataSource = dtFiles;
     gvResult.DataBind();
    
     }
     }
     else
     {
    ////แสดงข้อความแจ้งเตือนกรณีเกิดปัญหาไฟล์มีขนาดใหญ๋เกินกว่าที่กำหนดและไม่ใช่ชนิด image/jpeg
       lblUploadStatus.Text = "กรุณาเลือกไฟล์ที่ต้องการอัพโหลดให้เหมาะสม";
     }
     }
     catch (Exception ex)
     {
    ////แสดงข้อความแจ้งเตือนกรณีเกิดปัญหาในการอัพโหลดไฟล์
       lblUploadStatus.Text = "เกิดข้อผิดพลาดในการอัพโหลดไฟล์ :" + ex.Message;
     }
     }
     }
    }

    ตัวอย่างผลลัพธ์ที่ได้

    1) ก่อนทำการอัพโหลดไฟล์

    multiple4_5_0

    2) หลังอัพโหลดไฟล์ทั้งหมดเรียบร้อยแล้ว

    multiple4_5

    หมายเหตุ : หากกำหนดค่าให้กับ Properties ที่ชื่อว่า AllowMultiple=”false ตอนเลือกไฟล์ที่จะอัพโหลดจะสามารถเลือกได้เพียงไฟล์เดียวเท่านั้น

              จากบทความและตัวอย่างข้างต้น จะเห็นว่า ลักษณะผลลัพธ์ที่ได้จะคล้ายคลึงกัน แต่จะแตกต่างกันในส่วนของความซับซ้อนในการตรวจสอบความถูกต้องของข้อมูลไฟล์แนบที่รับเข้ามา ซึ่งผู้พัฒนาเองสามารถเลือกใช้วิธีที่ตนถนัดและขึ้นกับเวอร์ชั่นของ .NET Framework ที่กำลังพัฒนา รวมถึงเงื่อนไขของการตรวจสอบให้ตรงตามความต้องการของผู้ใช้มากที่สุด โดยเนื้อหาในบทความนี้เป็นเพียงแนวทางหนึ่งให้กับท่านในเบื้องต้นเท่านั้น ท่านสามารถนำไปประยุกต์ต่อยอดเพิ่มเติมได้ และผู้เขียนหวังเป็นอย่างยิ่งว่าบทความนี้จะเป็นประโยชน์กับผู้พัฒนาที่กำลังค้นหาวิธีการอัพโหลดไฟล์คราวละหลายไฟล์นี้อยู่เช่นกัน หากมีเนื้อหาส่วนใดผิดพลาด ผู้เขียนขออภัยไว้ ณ ที่นี้ด้วย ขอบคุณค่ะ ^^
    แหล่งข้อมูลอ้างอิง :
    http://www.aspsnippets.com/Articles/Uploading-Multiple-Files-using-JavaScript-Dynamic-FileUpload-Controls-in-ASP.Net.aspx
    http://www.codeproject.com/Articles/667604/Upload-multiple-files-in-asp-net
    http://www.c-sharpcorner.com/UploadFile/99bb20/upload-multiple-files-using-fileupload-control-in-Asp-Net-4/

  • การพัฒนา unit test โดย shim type

    Shims เป็นหนึ่งใน technology ที่อยู่ใน Microsoft Fakes Framework ใช้ในการพัฒนา unit testing เพื่อแยก component ที่ต้องการทดสอบออกมาจากปัจจัยแวดล้อมต่างรอบๆ component ในกระบวนการทดสอบ โดย shims จะทำการเปลี่ยนทิศทางการเรียกใช้ method ที่กำหนด ไปยัง code ที่เขียนขึ้นมาใช้ในการทดสอบ ส่วนใหญ่เราจะใช้ shims เพื่อแยก component ที่ต้องการทดสอบออกจาก assemblies ที่ไม่ได้เป็นส่วนหนึ่งของ solution ในการพัฒนา (กรณีที่ต้องการแยก component ที่ต้องการทดสอบออกจาก solution ของตัวเอง ควรจะใช้ stubs )

    method ที่พัฒนาส่วนใหญ่จะ return ผลการทำงานที่ต้องขึ้นกับเงื่อนไข ปัจจัยต่างๆจากภายนอก ในทางกลับกันสำหรับ shim  shim จะอยู่ภายใต้การควบคุมในกระบวนการทดสอบ สามารถที่จะ return ผลการทำงานตามที่กำหนดในทุกๆครั้งที่เรียกใช้งาน ซึ่งทำให้การเขียน unit testing ทำได้ง่ายขึ้นมาก

    ตัวอย่าง method การตรวจสอบวันที่เอกสารในปีงบประมาณ

    public static class Utility {
        public static bool IsInFiscalYear() {
            if (DateTime.Now < new DateTime(2015, 10, 1))
                return false;
            else
                return true;
        }
    }

    เมื่อต้องการทดสอบ method “IsInFiscalYear” จะพบว่าการทำงานของ method ขึ้นอยู่กับ DateTime.Now ซึ่งเป็นเวลาปัจุจบันที่ได้จากระบบ ซึ่งทำให้การทดสอบยุ่งยากขึ้น (เมื่อทำการทดสอบต้องเปลี่ยน DateTime เพื่อทำการทดสอบ ซึ่งอาจจะกระทบกับส่วนอื่นๆ ไม่สามารถทำการทดสอบแบบอัตโนมัติได้ ) ซึ่งการทดสอบ method ที่มีการเรียกใช้ database, web service ก็เช่นเดียวกัน เนื่องจากกลไกการทำงานขึ้นอยู่กับปัจจัยภายนอก ซึ่ง shim จะเข้ามาช่วยตรงจุดนี้

    Shim types จะให้กลไกการเปลี่ยนทิศทางการเรียกใช้ .NET method ไปยัง function ( หรือ user delegate) ที่เขียนขึ้น โดย shim types จะถูกสร้างโดย Fakes generator

    using (ShimsContext.Create()
    {
        ShimDateTime.NowGet = () => new DateTime(2016, 6, 1);
        var isIn = Utility.IsInFiscalYear();
    
        Assert.AreEqual(true, isIn);
    }

    ShimDateTime คือ shim type ที่ถูกสร้างโดย Fakes generator เพื่อใช้ในการกำหนดกลไกการทำงานแทน DateTime.Now

    การเพิ่ม Fakes Assemblies ใน solution ทำได้โดย

    1. ใน solution explorer ขยาย References ของ unit test project
    2. เลือก assembly ที่มี class ที่ต้องการสร้าง shim type (จากตัวอย่างนี้ต้องการสร้าง shim type ของ DateTime ให้เลือก System.dll)
    3. click ขวา เลือก Add Fakes Assembly

    ในการใช้ shim type ใน unit test framework จะต้องเขียน test code อยู่ใน ShimsContext เพื่อควบคุม lifetime ของ shim type (ถ้าไม่อยู่ภายใต้ ShimsContext, shim type จะคงอยู่จนกระทั่งปิดโปรแกรม) การสร้าง ShimsContext ทำได้โดยการเรียกใช้งาน static Create() ดังเช่นตัวอย่าง code ข้างต้น

    shim type สามารถใช้งานแทนที่ .NET method รวมทั้ง static method, instance method

    Static methods

    ShimMyClass.MyStaticMethod = () =>5;

    Instance methods สำหรับทุก instance

    ShimMyClass.AllInstances.MyMethod = () => 5;

    Instance methods แต่ละ instance

    var myClass1 = new ShimMyClass()
    {
        MyMethod = () => 5
    };

     

    อ้างอิง :

    • https://msdn.microsoft.com/en-us/library/hh549176.aspx
  • Auto remove schema in EDMX on build

    Entity Framework (EF)  คือ data access technology ที่เริ่มเปิดตัวครั้งแรกเป็นส่วนหนึ่งของ .NET Framework 3.5 SP1 โดยตัว EF จะทำหน้าที่เป็น object-relational mapper ที่ทำให้ผู้พัฒนาไม่จำเป็นต้องเขียน code ในส่วน data access ก็สามารถใช้ข้อมูลจาก relational database โดยผ่าน object model

    การพัฒนาโปรแกรมโดยใช้ EF นั้นจำเป็นต้องมี Entity Data Model เป็น model ที่กำหนดรายละเอียดเกี่ยวกับ entity และ relationship ระหว่าง entity นั้นๆ การสร้าง Entity Data Model สามารถแยกออกเป็น 2 แนวทางคือ “Code First” เป็นการกำหนดรูปร่างของ model โดยการสร้าง class (เขียน code) จะมี database หรือไม่มีอยู่ก่อนก็ได้  และ “Database First” ที่จะทำการสร้าง model ( reverse engineer) จาก database ที่มีอยู่โดย EF Designer ซึ่ง model ที่ได้จะเก็บอยู่ใน EDMX file (.edmx) สามารถเปิดหรือแก้ไขเพิ่มเติมได้ด้วย EF Designer สำหรับ class ที่ใช้ในโปรแกรมจะถูกสร้างโดยอัตโนมัติจาก EDMX file

    ข้อมูล Entity Data Model ใน EDMX file อยู่ในรูปแบบ xml สามารถแบ่งออกเป็น 3 ส่วนคือ Storage model, Conceptual model และ Mapping ซึ่งในส่วนของ Storage model จะเป็นข้อมูลรายละเอียดของ entity จาก database เช่น

    ข้อมูล EntityType ที่ให้รายละเอียดของชื่อของ entity (table ใน database), ชื่อและประเภทของ property (column ของ table ใน database)

     <EntityType Name="VF_CONFIG_REPORT">
      <Key>
        <PropertyRef Name="ID" />
      </Key>
        <Property Name="ID" Type="number" Precision="38" Scale="0" Nullable="false" />
        <Property Name="REPORT_NAME" Type="varchar2" MaxLength="512" />
        <Property Name="REPORT_PATH" Type="varchar2" MaxLength="512" />
        <Property Name="GROUP_TYPE" Type="number" Precision="38" Scale="0" />
        <Property Name="SIGN_NUM" Type="number" Precision="38" Scale="0" />
        <Property Name="SIGNS" Type="varchar2" MaxLength="128" />
     </EntityType>

    ข้อมูล EntitySet ที่ประกอบด้วย ชื่อ,ประเภทของ entity, schema และ query ที่ใช้ดึงข้อมูล

    <EntitySet Name="VF_CONFIG_REPORT" EntityType="Self.VF_CONFIG_REPORT" store:Type="Views" store:Schema="FINANCE">
       <DefiningQuery>
          SELECT 
           "VF_CONFIG_REPORT"."ID" AS "ID",
           "VF_CONFIG_REPORT"."REPORT_NAME" AS "REPORT_NAME", 
           "VF_CONFIG_REPORT"."REPORT_PATH" AS "REPORT_PATH", 
           "VF_CONFIG_REPORT"."GROUP_TYPE" AS "GROUP_TYPE", 
           "VF_CONFIG_REPORT"."SIGN_NUM" AS "SIGN_NUM", 
           "VF_CONFIG_REPORT"."SIGNS" AS "SIGNS"
         FROM "FINANCE"."VF_CONFIG_REPORT" "VF_CONFIG_REPORT"   
       </DefiningQuery>
    </EntitySet>

    เมื่อมีการระบุ schema ของ entityใน EDMX file  นั่นทำให้การ deploy ระบบ(โปรแกรมและ database) จำเป็นต้องมี database ที่มี schema ชื่อเดียวกับที่กำหนดใน EDMX file เท่านั้น(schema ได้มาจากการ generate ของ EF Designer ในขั้นตอนการพัฒนาระบบ) ถ้าต้องการให้ EF ทำงานกับ database schema อื่นจะต้องแก้ไข schema ใน EDMX file ให้ตรงกัน หรือไม่ระบุ schema โดยลบส่วนที่ระบุ schema ออก ซึ่งการแก้ไขจะต้องทำการแก้ไขโดยตรงไปที่ EDMX file แล้วทำการ build ใหม่ (ในกรณีที่ไม่ได้เลือก build EDMX file เป็นแบบ embeded resource สามารถแก้ไขที่ .ssdl file ได้โดยไม่ต้อง build ใหม่)

    ในการเปลี่ยน schema ใน EDMX file นั้นจะต้องแก้ทุก EntitySet ที่มี ทำให้มีความเสี่ยงที่จะเกิดความผิดพลาดในการแก้ไข ทำให้ระบบไม่สามารถทำงานได้ และถ้ามีความจำเป็นต้องปรับ Entity Data Model เพื่อเพิ่ม, แก้ไข หรือลบ entity ใดๆ EF Designer จะทำการ update .EDMX file ใหม่ ทำให้ schema ที่แก้ไขไปแล้วกลับมาเหมือนเดิม ต้องเปลี่ยน schema ใหม่อีกครั้ง ก็ยิ่งจะเพิ่มความเสี่ยงที่จะเกิดความผิดพลาด และยุ่งยากในการบริการจัดการ source code

    เราสามารถทำให้กระบวนการแก้ไขหรือลบ schema ใน EDMX file เป็นไปโดยอัตโนมัติ โดยการแก้ใข .csproj เพิ่มกระบวนการแก้ไขหรือลบ schema เข้าไปในขั้นตอนการ build ของ MsBuild หลังจากกระบวนการ “EntityDeployEmbededResource” ของ EF ดังนี้

     

    <Target Name="RemoveSchemaEntityDeployEmbeddedResources" AfterTargets="EntityDeployEmbeddedResources" Condition="'@(EntityDeployEmbeddingItems)' != ''">
      <PropertyGroup>
        <RemoveSchemaEmbeddedResources>"Libs\EFRemoveSchema" $(EntityDeployIntermediateResourcePath)%(EntityDeployEmbeddedResources.EntityDeployRelativeDir)</RemoveSchemaEmbeddedResources>
      </PropertyGroup>
      <Exec WorkingDirectory="$(MSBuildProjectDirectory)" Command="$(RemoveSchemaEmbeddedResources)" />
    </Target>

    “Libs\EFRomoveSchema” เป็นโปรแกรมเล็กๆที่พัฒนาเพื่อลบ schema ใน Entity Data Model ที่อยู่ใน folder   $(EntityDeployIntermediateResourcePath)%(EntityDeployEmbeddedResources.EntityDeployRelativeDir) โดยใช้ เทคนิคการค้นหา attribute ของ node ที่ต้องการใน XML file (EDMX file) เพื่อลบ และบันทึกกลับลงไปที่ XML file นั้นๆ

     

    อ้างอิง : https://msdn.microsoft.com/en-us/data/ee712907

  • ทำความรู้จักและเรียนรู้การใช้งานเบื้องต้นกับ StringBuilder ใน .NET Framework(C#)

              โดยปกติแล้วนั้น ผู้พัฒนาโปรแกรมโดยใช้ .NET Framework มักจัดการข้อมูลที่เป็นอักษรหรือข้อความ (String) ด้วยคลาสของ String ที่มีใน .NET Framework ซึ่งประกอบไปด้วยฟังก์ชั่นหรือเมธอดที่หลากหลายที่ติดมากับตัวคลาส เพื่อเตรียมมาไว้ให้ใช้งาน และสามารถรองรับความต้องการในการจัดการข้อมูลของผู้ใช้แต่ละคน ซึ่งมีวิธีการใช้งานง่าย ไม่ยุ่งยากซับซ้อน มีมาตรฐานการใช้งานที่รู้จักโดยทั่วถึงกัน สะดวกและรวดเร็วทำให้ผู้พัฒนาสามารถเลือกวิธีจัดการข้อมูลได้อย่างมีประสิทธิภาพ อย่างไรก็ตาม แม้ว่าคลาสของ String จะมีเมธอดให้เราได้เลือกใช้กันอย่างมากมายและมีประสิทธิภาพอยู่แล้ว แต่ปัญหาอย่างหนึ่งที่พบในการใช้งานกับตัวแปรของคลาส String คือ การเชื่อมต่อหรือเปลี่ยนแปลงแก้ไขค่าข้อความของตัวแปรชนิด String ในแต่ละครั้ง จะไม่สามารถเปลี่ยนรูป หรือกลับไปแก้ไขค่าของตัวแปรบนพื้นที่หน่วยความจำเดิมที่ถูกจองไว้ให้กับตัวแปรได้ หรืออาจพูดในทางโปรแกรมแบบง่ายๆได้ว่า หากเราต้องการเปลี่ยนแปลงค่าของตัวแปรชนิด String เราจะไม่สามารถกลับไปแก้ไขค่าใน object ของตัวแปรที่ถูกสร้างขึ้นเดิมในหน่วยความจำ หรือ Memory ที่สร้างไว้ในตอนแรกได้ แต่จะมีการสร้าง object ตัวใหม่ขึ้นมา ทุกครั้งที่มีการแก้ไข/จัดการข้อมูลค่า หรือมีการใช้งานเมธอดในคลาส System.String และใช้วิธีให้ pointer ของตัวแปรชี้ไปยังตำแหน่งของ object ตัวใหม่ที่มีค่าของตัวแปรที่ถูกแก้ไขภายหลังแทน ซึ่งหากมีกรณีที่มีการเปลี่ยนแปลงค่าข้อมูล หรือเชื่อมต่อข้อความในตัวแปรดังกล่าวจำนวนหลายครั้ง หรือมีการวนลูปซ้ำในการเปลี่ยนแปลงค่าเป็นจำนวนมาก จะถือเป็นการใช้งานทรัพยากรหน่วยความจำอย่างสิ้นเปลือง เนื่องจาก object ของตัวแปรจะถูกสร้างขึ้นใหม่เรื่อยๆและมีการจองพื้นที่ให้กับ object ตัวที่ถูกสร้างขึ้นใหม่ตามจำนวนครั้งที่ทำการแก้ไขหรือเชื่อมต่อข้อความนั่นเอง ดังภาพ


    ภาพการจองพื้นที่ในหน่วยความจำของตัวแปรชนิด String
    [ที่มาของภาพ : http://www.tutorialsteacher.com/csharp/csharp-stringbuilder]

                        จากภาพตัวอย่างจะเห็นได้ว่า เดิมทีมีการกำหนดค่าให้กับตัวแปรเป็นข้อความ “Hello World!!” แต่เมื่อมีการปรับแก้ค่าของตัวแปร จะมีการสร้าง object ตัวใหม่ โดยจะเก็บค่าที่มีการเปลี่ยนแปลงของข้อความไปเป็น “Hello World!! From Tutorials Teacher” และเลื่อนตำแหน่งของ pointer ของตัวแปรที่จะชี้ไปเพื่อให้ได้ค่าใหม่นั่นเอง
              จากปัญหาดังกล่าว .NET Framework ก็ได้จัดเตรียมคลาสที่มีชื่อว่า “StringBuilder” ขึ้นมา ซึ่งเป็นคลาสที่ใช้ในการจัดการกับข้อมูลชนิดข้อความเช่นเดียวกับคลาส String โดยยินยอมให้มีการแก้ไขและปรับเปลี่ยนค่าในตัวแปรข้อความ(string) ดังกล่าวได้ใน object ตัวเดิมบนพื้นที่หน่วยความจำเดิม โดยไม่ต้องสร้าง object และทำการจองพื้นที่หน่วยความจำขึ้นใหม่ทุกครั้งที่มีการเปลี่ยนแปลงค่าของข้อความดังเช่นในคลาส String นั่นเอง ซึ่งจะทำให้สามารถประหยัดการใช้ทรัพยากรหน่วยความจำได้ในกรณีที่มีการเชื่อมต่อข้อความหรือเปลี่ยนแปลงค่าของตัวแปรจำนวนหลายครั้งได้

     ภาพการจองพื้นที่ในหน่วยความจำของตัวแปรชนิด StringBuilder

    [ที่มาของภาพ : http://www.tutorialsteacher.com/csharp/csharp-stringbuilder]

              ดังนั้น ในการจัดการข้อมูลที่เป็นตัวอักษร หรือข้อความ ผู้พัฒนาควรเลือกใช้วิธีการให้เหมาะสมกับประเภทและลักษณะการใช้งาน เพื่อให้การใช้งานบนพื้นที่หน่วยความจำ และทรัพยากรเกิดประสิทธิภาพสูงสุด ซึ่งในบทความนี้ ผู้เขียนจะขอพูดถึงวิธีการใช้งานในเบื้องต้นของการจัดการข้อมูลชนิด StringBuilder เพื่อเป็นอีกหนึ่งทางเลือกให้กับผู้พัฒนาต่อไป

     

    หลักการทำงานและการจองพื้นที่ในหน่วยความจำของตัวแปรชนิด StringBuilder

              โดยปกติแล้วนั้น ค่าของ “StringBuilder.Length” จะเป็นค่าของจำนวนตัวอักษรที่มีในตัวแปร object ของ StringBuilder และจะถูกเพิ่มขึ้นเรื่อยๆ เมื่อมีการเพิ่มตัวอักษรหรืออักขระเข้าไปในตัวแปรนั้นโดยไม่มีการจองพื้นที่หน่วยความจำเพิ่ม จนกว่าค่าของ Length เท่ากับจำนวนของความจุที่จองพื้นที่หน่วยความจำไว้ ซึ่งก็หมายถึงค่าของ “Capacity” นั่นเอง และหากการเพิ่มตัวอักษรดังกล่าวทำให้ค่าของ Length มากกว่าค่าของ Capacity ใน object นั้นๆ จะมีการจองพื้นที่หน่วยความจำเพิ่มเป็นเท่าตัว เช่น จากเดิม 16 ตัวอักษรจะถูกเพิ่มเป็น 32 ตัวอักษร โดยจะสามารถเปลี่ยนแปลงได้ไม่เกินค่าความจุสูงสุด หรือที่เรียกว่า “MaxCapacity” ซึ่งถ้าหากมีการเพิ่มตัวอักษรที่เกินค่าของ MaxCapacity แล้วนั้นจะทำให้เกิดข้อผิดพลาดได้ แต่หากไม่มีการกำหนดค่าให้กับ Capacity และ MaxCapacity แล้วนั้น ค่าตั้งต้นของ Capactity เริ่มต้นจะอยู่ที่ 16 ตัวอักษร และค่าของ MaxCapacity จะอยู่ที่ประมาณ 2 พันล้านตัวอักษร หรือเทียบเท่ากับค่าสูงสุดของ Int32.MaxValue นั่นเอง

    การอ้างอิง Namespace
    โดย Namespace ที่ต้องอ้างอิงเพิ่มเติมในการใช้งานคลาส StringBuilder มีดังนี้

    • using System;
    • using System.Text;

    การประกาศตัวแปรของคลาส StringBuilder
    ในการประกาศตัวแปร object ของคลาส StringBuilder จะใช้หลักการเดียวกันกับการประกาศตัวแปร object ของคลาสโดยทั่วไป แต่สามารถประกาศโดยมีการระบุค่าอื่นเพิ่มเติมโดยใช้ Constructor ได้ ซึ่งจะขอยกตัวอย่างในกรณีที่มีการใช้งานกันโดยทั่วไป ดังนี้
    แบบเดียวกับการประกาศ object ของคลาสทั่วไป
    ตัวอย่าง

    StringBuilder sb = new StringBuilder();

    แบบมีการกำหนดค่าตั้งต้น
    ตัวอย่าง

    StringBuilder sb = new StringBuilder("Hello World!!");

    คำอธิบาย : เป็นการสร้างตัวแปร object แบบมีการกำหนดค่าเริ่มต้นให้มีค่าเท่ากับ Hello World!!
    แบบมีการระบุขนาดในการจองพื้นที่ของหน่วยความจำ(Capacity)  แม้ว่าตัวแปรของคลาส StringBuilder สามารถเพิ่มและขยายได้ไม่จำกัดโดยไม่ต้องสร้าง object ตัวใหม่ แต่ผู้พัฒนาสามารถระบุขนาดสูงสุดของจำนวนตัวอักษรที่ตัวแปรจะสามารถรองรับได้ โดยค่าดังกล่าวที่ระบุนี้ เรียกว่า “Capacity” และเรียกค่าของความยาวตัวอักษรที่มีในตัวแปรนั้นๆ โดยใช้ properties ที่มีชื่อว่า “Length” โดยหากมีการกำหนดค่าของ Capacity ให้กับตัวแปรคลาส StringBuilder เมื่อมีการแก้ไขค่าของตัวแปรจะไม่ถูกจองพื้นที่ใหม่จนกว่าความยาวของตัวอักษรจะถึงค่าของ Capacity ที่กำหนด จึงจะมีการจองพื้นที่ใหม่ให้อัตโนมัติในขนาดเดียวกับ Capacity ที่กำหนดไว้เดิมเป็นเท่าตัว แต่หากไม่ได้ทำการกำหนดค่าของ Capacity ไว้ จะมีค่า default เท่ากับ 16 ซึ่งสามารถกำหนดค่าของ Capacity ได้ดังนี้

    StringBuilder sb = new StringBuilder(25);

    คำอธิบาย : เป็นการสร้างตัวแปร object แบบมีการกำหนดขนาดของตัวแปรให้มีขนาดความจุ หรือ Capacity ไว้ที่ 25 ตัวอักษร แต่หากมีการกำหนดค่าของข้อมูลที่มีความยาวตัวอักษรมากกว่าขนาดที่กำหนด จะมีการขยายพื้นที่ความจุให้กับขนาดตัวแปรอัตโนมัติ นอกจากจะสามารถกำหนดขนาดของตัวแปร StringBuilder โดยใช้ Constructor แล้วนั้นยังสามารถระบุผ่าน Properties ที่มีชื่อว่า Capacityได้อีกด้วย ดังนี้

    sb.Capacity = 25;

    แบบกำหนดค่าเริ่มต้นและระบุขนาดความจุของตัวแปร
    ตัวอย่าง

    StringBuilder sb = new StringBuilder("Hello World!", 25);

    คำอธิบาย : เป็นการประกาศตัวแปรขนาด 25 ตัวอักษร และมีค่าเริ่มต้นเป็นคำว่า “Hello World!!”

    แบบกำหนดค่าขนาดความจุและความจุสูงสุดของพื้นที่หน่วยความจำให้กับตัวแปร
    ตัวอย่าง

    StringBuilder sb = new StringBuilder( 25,200);

    คำอธิบาย : เป็นจองพื้นที่ในการประกาศตัวแปร(Capacity)ขนาด 25 ตัวอักษร และมีค่าความจุสูงสุด(MaxCapacity)ได้ไม่เกิน 200 ตัวอักษร

    แบบกำหนดค่าเริ่มต้นที่มีการตัดข้อความ(substring) และระบุขนาดความจุของตัวแปร
    ตัวอย่าง

    StringBuilder sb = new StringBuilder("Hello World!",0,5, 25);

    คำอธิบาย : เป็นจองพื้นที่ในการประกาศตัวแปรขนาด 25 ตัวอักษร และมีค่าเริ่มต้นเป็นคำว่า “Hello”

    เนื่องจากมีการ substring ค่าข้อความ “Hello World!!” ตั้งแต่ตำแหน่งที่ 0 มา 5 ตัวอักษร จึงกลายเป็นคำว่า “Hello” นั่นเอง

    เมธอดที่จำเป็นและควรรู้ในการใช้งานคลาส String builder

    โดยแบ่งตามลักษณะการทำงาน เพื่อง่ายต่อความเข้าใจและการนำไปใช้ ดังนี้

    1.การเชื่อมต่อข้อความ เป็นการเชื่อมต่อข้อความกับค่าตัวแปรที่มีอยู่เดิมที่ตำแหน่งท้ายสุด ซึ่งมีเมธอดที่ใช้งานกันบ่อย ดังนี้
    • Append() เป็นเมธอดที่ใช้ในการเชื่อมข้อความ ซึ่งสามารถใช้แทนการต่อสตริงหรือข้อความแบบทั่วไปในคลาส String โดยจะไปต่อตรงส่วนท้ายสุดของค่าใน object โดยไม่ต้องเปลี่ยนการจองพื้นที่หน่วยความจำ
    ตัวอย่างที่ 1

    StringBuilder sb = new StringBuilder("Hello World!");
    sb.Append(" Nice to meet you!!");
    Console.WriteLine(sb);

    คำอธิบาย : จากตัวอย่างข้างต้น จะเห็นว่าเดิมค่าของตัวแปรมีค่า “Hello World!” แต่เมื่อมีการเรียกใช้เทธอด Append() จะทำการต่อข้อความจากเดิมจนกลายเป็น “Hello World! Nice to meet you!!

    ตัวอย่างที่ 2

    StringBuilder sb = new StringBuilder("Hello World");
    sb.Append(" !?!?",2,2);
    Console.WriteLine(sb);

    คำอธิบาย : จากตัวอย่างข้างต้น จะเห็นว่าเดิมค่าของตัวแปรมีค่า “Hello World” แต่เมื่อมีการเรียกใช้เมธอด Append() แบบมีการ substring ร่วมด้วย โดยจะเริ่มทำการตัดตัวอักษรจากข้อความ “ !?!?” จากตำแหน่งลำดับ index ที่ 2 ไป 2 ตัวอักษร ซึ่งนั่นก็คือ “?!” หลังจากนั้นก็จะเชื่อมต่อด้วยข้อความเดิมจนกลายเป็น “Hello World!?!

    AppendLine() เป็นเมธอดที่ใช้ในการแทรกบรรทัดใหม่เข้าไปให้กับตัวแปร
    ตัวอย่าง

    StringBuilder sb = new StringBuilder("Hello, I am Kate.");
    sb.AppendLine();
    sb.Append("Nice to meet you.");
    Console.WriteLine(sb);
    
    //หรือ
    StringBuilder sb = new StringBuilder("Hello, I am Kate.");
    sb.AppendLine("Nice to meet you.");
    Console.WriteLine(sb);
    
    

    คำอธิบาย : จากตัวอย่างข้างต้น จะเป็นการเพิ่มการขึ้นบรรทัดใหม่ให้กับข้อความของตัวแปร จากค่า “Hello, I am Kate.” ด้วยการขึ้นบรรทัดใหม่ ตามด้วยข้อความ “Nice to meet you.” โดยแสดงทั้งตัวอย่างที่มีการเพิ่มบรรทัดโดยใช้เมธอด AppendLine() ก่อน แล้วจึงเชื่อมข้อความที่เหลือด้วยเมธอด Append() หรืออาจรวบวิธีการขึ้นบรรทัดใหม่ต่อด้วยข้อความด้วยการใช้เมธอด Appendline() แบบมีการส่งค่าพารามิเตอร์ของข้อความที่ต้องการเชื่อมต่อหลังจากขึ้นบรรทัดใหม่ได้เลยดังตัวอย่าง

    AppendFormat() เป็นเมธอดที่ใช้ในการเชื่อมต่อข้อความที่ท้ายสุดของค่าเดิม แบบที่มีการจัดรูปแบบให้กับข้อความที่ต้องการนำมาเชื่อมต่อ โดยรูปแบบที่ใช้ในการกำหนดเป็นรูปแบบมาตรฐานที่ใช้ในการกำหนดรูปแบบของข้อมูลที่เป็นตัวเลข วันที่ และเวลา เป็นต้น
    ตัวอย่าง

    int MyInt = 25;
    StringBuilder sb = new StringBuilder("Your total is ");
    sb.AppendFormat("{0:C} ", MyInt);
    Console.WriteLine(sb);
    

    คำอธิบาย จากตัวอย่าง เป็นการจัดรูปแบบของข้อมูลที่จะนำมาทำการเชื่อมต่อกับตัวแปรเดิม โดยผลลัพธ์ที่ได้ คือ Your total is $25.00 นั่นเอง

    Insert() เป็นเมธอดที่ใช้ในการเพิ่มค่าข้อความแทรกไปยังตัวแปร โดยมีการกำหนดตำแหน่งเริ่มต้นที่ต้องการให้แทรกเพิ่มในค่าข้อมูลดังกล่าวเข้าไปในตัวแปร StringBuilder นั้นด้วย
    ตัวอย่าง

    StringBuilder sb = new StringBuilder("Hello, I am Kate.");
    sb.Insert(5," Mr.Kim");
    Console.WriteLine(MyStringBuilder);

    คำอธิบาย : จากตัวอย่างข้างต้น จะเป็นการแทรกข้อความ “ Mr.Kim” ลงในตัวแปร sb ที่มีค่าเดิมเป็น
    Hello, I am Kate.” จนได้ผลลัพธ์ คือ “Hello Mr.Kim, I am Kate.”

    2.การล้างค่าหรือเอาค่าข้อมูลบางส่วนออก  เป็นการล้างค่าข้อมูลของตัวแปร หรือตัดข้อมูลของตัวแปรบางส่วนออกไป โดยเมธอดที่ใช้งานกันบ่อย มีดังนี้

    Clear() เป็นเมธอดที่ใช้ในการล้างค่าตัวอักษรในข้อความของตัวแปร String builder ดังกล่าว และกำหนดค่าให้กับความยาวตัวอักษรหรือ properties ที่มีชื่อว่า “Length เป็น 0
    ตัวอย่าง

    StringBuilder sb = new StringBuilder("Hello World!");
    sb.Clear();
    Console.WriteLine(sb);

    คำอธิบาย : จากตัวอย่างข้างต้นจะเป็นการล้างค่าข้อมูลให้กับตัวแปร sb จากเดิมที่มีค่าตั้งต้นเป็น “Hello World!” จะเหลือเป็นค่าว่าง หรือ String.Empty และหากต้องการให้แสดงผลจะไม่แสดงข้อความใดๆขึ้นมา แต่ยังคงจองพื้นที่หน่วยความจำไว้ให้กับตัวแปรนี้แม้จะไม่มีค่าข้อมูลใดๆก็ตาม และจะมีค่า Length เป็น 0 นั่นเอง

    Remove() เป็นเมธอดที่ใช้ในการตัดค่าของข้อความในตัวแปรออก โดยมีการกำหนดตำแหน่งเริ่มต้นและความยาวของตัวอักษรในข้อความที่ต้องการตัด โดยนับตำแหน่งจากตัวอักษรตัวแรกเป็นค่าตำแหน่งลำดับที่ 0(ซึ่งเป็นการอ้างอิงตามหลักการนับตำแหน่งของ index โดยเริ่มถือว่าตัวอักษรตัวแรกเป็น index ลำดับที่ 0 นั่นเอง)
    ตัวอย่าง

    StringBuilder sb = new StringBuilder("Hello World!");
    sb.Remove(5,7);
    Console.WriteLine(sb);
    

    คำอธิบาย : จากตัวอย่างข้างต้น เดิมตัวแปรมีค่าข้อความเป็น “Hello World!” แต่เมื่อใช้เมธอด Remove() ในการตัดค่าข้อความตั้งแต่ตำแหน่งของลำดับ index ที่ 5 (หรือตำแหน่งที่ 4 เมื่อเริ่มต้นนับ 1 จากตัวอักษรแรกของข้อความ) ไปจำนวน 7 ตัวอักษร โดยผลลัพธ์ที่ได้ เป็นดังนี้ “Hello

    • การตัดค่าบางส่วนออกโดยกำหนดค่า properties ที่ชื่อว่า Length ให้กับตัวแปร

    ตัวอย่าง

    StringBuilder sb1= new StringBuilder("Hello World!");
    sb1.Length--;
    //หรือ
    sb1.Length = sb1.Length-1;
    //หรือ
    sb1.Remove(sb1.Length-1,1);
    //เป็นการตัดค่าตัวอักษรตัวสุดท้ายออกจากข้อความ จะได้ผลลัพธ์ คือ Hello World 
    
    StringBuilder sb2= new StringBuilder("Hello World!"); 
    sb2.Length=0; 
    //เป็นการล้างค่าข้อมูลในตัวแปร sb2 
    ซึ่งจะมีลักษณะการทำงานเช่นเดียวกับการใช้เมธอด Clear() ที่กล่าวไว้แล้วข้างต้นนั่นเอง

    คำอธิบาย : จากตัวอย่างข้างต้น ในส่วนของ sb1 นั้นจะเป็นการตัดค่าตัวอักษรตัวสุดท้ายออกจากข้อความ “Hello World!” ซึ่งก็คือตัวอักษร “!” โดยจะได้ผลลัพธ์ เป็น “Hello World” และสำหรับกรณีของ sb2 จะเป็นการล้างค่าข้อมูลในตัวแปร sb2 ซึ่งจะมีลักษณะการทำงานเช่นเดียวกับการใช้เมธอด Clear() ที่กล่าวไว้แล้วข้างต้นนั่นเอง

    3. การเปลี่ยนแปลงค่าของตัวแปร  ดังนี้

    • Replace() เป็นเมธอดที่ใช้ในการแทนที่ข้อความ โดยมีลักษณะการทำงานเช่นเดียวกับเมธอด Replace() ที่มีในคลาส String ที่จะต้องมีการกำหนดค่าใหม่ที่ต้องการให้แทนที่ และค่าที่ต้องการแทนที่นั่นเอง
    ตัวอย่าง

    StringBuilder sb= new StringBuilder("Hello World!");
    sb.Replace('World', 'Kate');
    Console.WriteLine(sb);
    

    คำอธิบาย จากตัวอย่างข้างต้น จะเป็นการแทนที่ค่าของข้อความเดิมคือ “World” ในคำว่า “Hello World!” ด้วยค่า “Kate” ซึ่งจะได้ผลลัพธ์ คือ “Hello Kate!

    4. การแปลงค่าจากตัวแปรชนิด StringBuilder เป็น String  ดังนี้

    ToString() เป็นเมธอดที่ใช้ในการแปลงค่าตัวแปรแบบ StringBuilder มาเป็นค่าของตัวแปรแบบคลาส String เพื่อนำไปแสดงผลหรือนำมาประยุกต์ใช้งานกับเมธอดที่มีในคลาส String ต่อไป
    ตัวอย่าง

    StringBuilder sb= new StringBuilder("Hello World!");
    Console.WriteLine(sb.ToString());
    //การนำไปใช้กับเมธอดหรือฟังก์ชั่นที่มีในคลาส String
    int a = sb.ToString().IndexOf("a");
    //เป็นการค้นหาตำแหน่งของอักษร a ในตัวแปร sb ที่ถูกแปลงเป็น String 
    ซึ่งผลลัพธ์ที่ได้จะเท่ากับ -1 เนื่องจากไม่มีตัวอักษร a ในข้อความดังกล่าว

    คำอธิบาย : จากตัวอย่างข้างต้นเป็นการแปลงค่าของตัวแปรในคลาส StringBuilder ให้เป็นคลาส String ซึ่งหลังจากที่ได้ทำการแปลงค่าแล้วนั้น จะสามารถใช้งานเมธอหรือฟังก์ชั่นที่มีในคลาส String ได้ เช่น IndexOf หรือ StartsWith  เป็นต้น

    5. การอ้างอิงและเข้าถึงตัวอักษรที่อยู่ในข้อความ  ดังนี้

    ตัวอย่าง

    StringBuilder sb= new StringBuilder("Hello World!");
    Console.WriteLine(sb[6]);
    //ผลลัพธ์ที่ได้คือ "W"
    sb[2] = 'k';
    //ผลลัพธ์ที่ได้คือ "Heklo World!"

    คำอธิบาย : จากตัวอย่างข้างต้นเป็นการเข้าถึงตำแหน่งของค่าตัวแปรชนิด StringBuilder ผ่านการอ้างลำดับ index ของอักขระในตัวแปรนั้น และตัวอย่างถัดมาจะเป็นการเปลี่ยนแปลงค่าโดยการเข้าถึงอักขระในลำดับ index ที่กำหนด โดยให้ค่าใหม่แทนที่

    6. การค้นหา  ในการค้นข้อมูลของตัวแปรแบบ StringBuilder นั้น โดยทั่วไปแล้วจะไม่มีเมธอดที่ใช้ในการค้นหาข้อมูลโดยตรง ดังเช่นที่มีในคลาส String เช่น IndexOf หรือ StartsWith ดังนั้นเราสามารถประยุกต์วิธีการค้นหาตามลักษณะของข้อมูลและการจัดการได้ ดังนี้

    • การค้นหาค่าที่ได้กลับมาในรูปแบบ Stringจากการเรียกใช้เมธอด ToString() โดยใช้เมธอดที่มีเช่นเดียวกับในคลาส String ซึ่งเป็นวิธีที่ง่าย และสามารถเปลี่ยนแปลงข้อมูลของตัวแปรได้โดยไม่สิ้นเปลืองทรัพยากร
    • แปลงค่าของตัวแปรแบบ StringBuilder ให้เป็นแบบ String และใช้เมธอดในการค้นหาที่มีในคลาส String ซึ่งวิธีการนี้เหมาะกับการทำงานที่ไม่มีการเปลี่ยนแปลงภายหลังจากการแปลงค่ามากนัก เพื่อลดการสิ้นเปลืองทรัพยากรในการแปลงค่าภายหลัง
    • ค้นหาข้อมูลให้เสร็จก่อนทำการนำมาแปลงค่าเป็นแบบ StringBuilder โดยวิธีนี้จะต้องไม่สนใจค่าลำดับของตัวอักษรที่ได้จากการค้นหานั้นๆ
    • ค้นหาโดยใช้ Properties ทีชื่อว่า Chars โดยวิธีนี้เหมาะกับข้อมูลที่มีอักษรจำนวนไม่มาก และเงื่อนไขในการค้นหาไม่ซับซ้อน

    เพิ่มเติม
    • หลักการเบื้องต้นในการพิจารณาการใช้งานกับการจัดการข้อมูลของตัวแปรข้อความ(String)ที่ใช้เมธอดการทำงานในแบบเดียวกัน หากเป็นการใช้งานที่มีการเชื่อมต่อข้อความในตัวแปรเดิมที่มากกว่า 4 ครั้ง ผู้พัฒนาควรหันมาใช้ตัวแปรแบบคลาส StringBuilder เนื่องจากจะทำให้ประหยัดทรัพยากรหน่วยความจำมากกว่า แต่หากจำนวนครั้งในการเชื่อมต่อน้อยกว่านั้นควรใช้คลาสของ String ตามเดิมเพื่อความสะดวกและรวดเร็ว เนื่องจากมีเมธอดรองรับการจัดการข้อความที่หลากหลายและไม่ถือเป็นการสิ้นเปลืองพื้นที่หน่วยความจำมากนัก

    • ในการเรียกใช้งานเมธอดต่างๆ สามารถนำมาเขียนรวมกันใน statement เดียวกันได้ ดังนี้

    ตัวอย่างที่ 1

          StringBuilder sb = new StringBuilder();
          sb.Append("This is the beginning of a sentence, ");
          sb.Replace("the beginning of ", "");
          sb.Insert(sb.ToString().IndexOf("a ") + 2, "complete ");
          sb.Replace(",", ".");
          Console.WriteLine(sb.ToString());
    

    คำอธิบาย : จากตัวอย่างข้างต้นเป็นการเชื่อมต่อข้อความเริ่มต้น คือ “This is the beginning of a sentence, ” และแทนที่คำว่า  “the beginning of” ด้วย “”(ค่าว่าง) และแทรกข้อความคำว่า “complete ” เข้าไปในตำแหน่งซึ่งหามาได้จากการเรียกใช้เมธอด ToString() และตามด้วยเมธอด IndexOf ของตำแหน่งข้อความ “a ” ถัดไปอีก 2 ตำแหน่งด้วยค่า “complete ” และแทนที่เครื่องหมาย “,” ด้วย “.”

    สามารถเขียนรวมเป็น statement เดียวกันได้ดังนี้

    ตัวอย่างที่ 2

          StringBuilder sb = new StringBuilder("This is the beginning of a sentence, ");
          sb.Replace("the beginning of ", "").Insert(sb.ToString().IndexOf("a ") + 2, 
                                                     "complete ").Replace(",", ".");
          Console.WriteLine(sb.ToString());

    ซึ่งจะให้ผลลัพธ์เช่นเดียวกับตัวอย่างที่ 1

              จากบทความข้างต้นที่กล่าวมาทั้งหมด จะเห็นได้ว่าประสิทธิภาพการจัดการข้อมูลจะดีเพียงใดนั้น ย่อมขึ้นอยู่กับการพิจารณาและเลือกใช้วิธีการจัดการข้อมูลที่ถูกต้องและเหมาะสมกับปัจจัยต่างๆ เช่น จำนวนของข้อมูล จำนวนครั้งในการเปลี่ยนแปลงข้อมูล และจำนวนทรัพยากรที่ใช้ในการพัฒนา เป็นต้น ซึ่งข้อมูลในบทความนี้เป็นเพียงข้อมูลในเบื้องต้นเกี่ยวกับ StringBuilder เท่านั้น ยังคงมีข้อมูลรอให้พวกเรานักพัฒนาทั้งหลายได้เข้าไปทำการศึกษาและเรียนรู้กันอีกมากมาย หากผู้ใดมีความสนใจสามารถค้นหาเพิ่มเติมและมาร่วมกันแบ่งปันประสบการณ์ร่วมกันได้ และผู้เขียนหวังเป็นอย่างยิ่งว่าข้อมูลดังกล่าวจะช่วยให้การตัดสินใจเลือกใช้วิธีการจัดการข้อมูลเป็นไปได้ง่ายขึ้น และโปรแกรมที่พัฒนาทำงานได้มีประสิทธิภาพรวดเร็วขึ้นไม่มากก็น้อย หากผิดพลาดประการใด ผู้เขียนขออภัยมา ณ ที่นี้ด้วยค่ะ

    แหล่งข้อมูลอ้างอิง :
    http://www.dotnetperls.com/stringbuilder
    https://msdn.microsoft.com/en-us/library/2839d5h5(v=vs.110).aspx
    http://www.tutorialsteacher.com/csharp/csharp-stringbuilder
    https://blog.udemy.com/stringbuilder-c-sharp/

  • ASP.NET MVC Part 4: ทำความรู้จักกับ ViewData, ViewBag และ TempData

    การส่งผ่านข้อมูลระหว่างกันใน ASP.NET MVC จะมีการส่งผ่านกันด้วย objects ซึ่งใน ASP.NET MVC จะมี object ที่ชื่อ ViewData, ViewBag และ TempData เป็น object ที่่ใช้ในการส่งผ่านข้อมูลในลักษณะที่แตกต่างกันออกไป โดยในการส่งผ่านข้อมูลจะแบ่งได้เป็น 3 กรณี คือ

    • การส่งผ่านค่าจาก Controller ไปยัง View
    • การส่งผ่านค่าจาก Controller หนึ่ง ไปยัง Controller อื่น
    • การส่งค่าระหว่าง Action หนึ่ง ไปยัง Action อื่น

    โดยทั้ง 3 objects จะมีคุณสมบัติที่แตกต่างกัน ดังนี้

    1. ViewBag เป็น dynamic object ในการส่งค่าจาก controller ไปยัง view
    2. ViewData เป็น dictionary object ในการส่งค่าจาก controller ไปยัง view
    3. TempData เป็น dictionary object ในการส่งค่าข้ามกันระหว่าง controller และ action

     

    การส่งผ่านข้อมูลจาก controller ไปยัง View

    การส่งผ่านข้อมูลจาก Controller ไปยัง View สามารถทำได้ 3 รูปแบบ ขึ้นอยู่กับลักษณะของข้อมูลที่ต้องการส่งว่าเป็นข้อมูลลักษณะไหน มีความซับซ้อนเพียงใด แต่ละรูปแบบสามารถเขียนได้ดังนี้

    controllertoview

     

    ส่งผ่าน Model

    การส่งผ่านข้อมูลผ่านตัว model เป็นการส่งผ่านข้อมูลผ่านตัว model ตรงๆ โดยที่ข้อมูลจะมี property ตามที่มีอยู่ใน model ที่สร้างไว้ ดังตัวอย่าง สร้าง model ของ Book และ set ค่าให้กับ property ต่างๆ และ return model Book ไปยังหน้า View

    ฝั่ง Controller

    public ActionResult Index()
            {
                List<ฺBook> b = new List<Book>() {
     
                   new Book{ Id = 1, Title = "Harry Potter", Author= "JK. Rolling"},
                   new Book{ Id = 2, Title = "Inferno", Author= "Dan Brown"}
                };
     
                return View(b);
            }
    

    ฝั่งแสดงผล View

    ประกาศ type ของ model เป็น Book หลังจากนั้นใช้ตัวแปร model ในการเข้าถึง property ต่างๆของ Model

    @model MvcBook.Models.Book
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            th>
            <th>
                @Html.DisplayNameFor(model => model.Author)
            th>
            <th>th>
        tr>
     
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            td>
            <td>
                @Html.DisplayFor(modelItem => item.Author)
            td>
        tr>
    }
     
    table>
    

     

    ส่งผ่าน ViewBag

    การส่งผ่านข้อมูลด้วย ViewBag จะเป็นการส่งข้อมูลที่เป็น dynamic object เช่น string, int, float เป็นต้น ดังตัวอย่าง

    ฝั่ง Controller

    public ActionResult Index()
            {
                ViewBag.title = "THE DAVINCI CODE";
                return View();
            }
    

    ฝั่งแสดงผล View

    <h2>@ViewBag.Title</h2>
    

     

    ส่งผ่าน ViewData

    การส่งผ่านข้อมูลด้วย ViewData จะเป็นการส่งข้อมูลที่เป็น dictionary object เช่น List, Enumerable, array เป็นต้น ดังตัวอย่าง

    ฝั่ง Controller

    public ActionResult Index()
            {
                List<string> listBook = new  List<string>();
                listBook.Add("Davinci code");
                listBook.Add("The lost symbol");
                listBook.Add("Inferno");
                ViewData["ListBook"] = listBook;
                return View();
            }
    

    ฝั่งแสดงผล View

    ในการแสดงผลข้อมูลที่เป็น dictionary object นั้นให้ทำการ cast ให้เป็น type ที่ตรงกับ type ที่ส่งมาจาก controller

    <table class="table"> 
    @foreach (var item in (List<string>)ViewData["ListBook"]) {
        <tr>
            <td>
                @item
            td>
        tr>
    }
    <table>
    

     

    การส่งผ่านข้อมูลจาก controller/Action หนึ่ง ไปยัง controller/Action อื่น

    ในการส่งผ่านข้อมูลจาก controller หนึ่ง ไปยังอีก controller หรือจาก action ไปยังอีก action จะใช้ object ที่ชื่อ TempData ในการส่งค่าระหว่างกัน ซึ่ง TempData จะเก็บข้อมูลใน session โดยเป็นการส่งค่าจาก HTTP request หนึ่งไปยัง HTTP request อื่นๆ ดังตัวอย่าง

    tempdata

    controller ฝั่งส่งค่า

    public ActionResult Index()
            {
              TempData["data1"] = "I am from action 1";
              return RedirectToAction("Read");
             
            }
    

    controller ฝั่งรับค่า

    public string Read()
            {
                string str;
                str = TempData["data1"].ToString();
                return str;
            }
    

     

    สรุป

    ในการส่งข้อมูลระหว่าง controller กับ view และ controller/action กับ controller/action ของ ASP.NET MVC นั้น ในเบื้องต้นสามารถส่งผ่าน object ทั้ง 3 ตัว ได้แก่ ViewBag, ViewData และ TempData โดยในการเลือกใช้ให้พิจารณาลักษณะของข้อมูลที่ต้องการส่งเป็นหลัก

    บทความก่อนหน้า : ASP.NET MVC Part3: สร้าง Model ด้วย Entity Framework

    แหล่งอ้างอิง : 

    [1] http://www.codeproject.com/Articles/476967/What-is-ViewData-ViewBag-and-TempData-MVC-Option?msg=4858421

    [2] http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp-net-mvc-3-applications/

  • ตอนที่ 3 : สร้างรายงานด้วย Business Intelligence Development Studio (BIDS)

         เครื่องมือที่ใช้สำหรับสร้างรายงาน ได้แก่ Business Intelligence Development Studio (BIDS) และ Report Builder ในตอนที่นี้จะกล่าวถึงการสร้างรายงานด้วย BIDS ซึ่งเป็นอินเตอร์เฟซ ของ Microsoft Visual Studio เหมาะสำหรับนักพัฒนาที่คุ้นเคยกับ Microsoft Visual Studio ส่วน Report Builder เป็นโปรแกรมสำหรับสร้างรายงาน เหมาะกับผู้ใช้ทั่วๆไปที่ใช้ในทางธุรกิจเป็นหลัก

    การสร้างรายงานมีขั้นตอน ดังต่อไปนี้

    ขั้นตอนที่ 1 : Create Report Server Project

    • ไปที่ File > New > Project… ดังรูปที่ 1
    • จะได้ผลลัพธ์ ดังรูปที่ 2

    3-1

    รูปที่1 Create Report Server Project

    3-2

    รูปที่2 Report Server Project Solution

    ขั้นตอนที่ 2 : Create new report 
    การสร้างไฟล์รายงาน เราสามารถทำได้ 2 แบบคือ

     แบบที่1 สร้างไฟล์รายงานว่างๆ (empty report) ดังนี้

     1. จากรูปที่ 2 คลิกขวาที่โฟลเดอร์ Report > Add > New Item… > เลือก Create a new empty report ดังรูปที่ 3

    3-3

      รูปที่3 Create a new empty report

    2. ไปที่หน้าต่าง Report Data (View > Report Data) เพื่อสร้าง Data Sources และ Datasets

             – คลิกขวาโฟลเดอร์ Data Sources > Add Data Source… ซึ่งสามารถสร้าง Connection ได้ 2 แบบ คือ

              1. Embedded Connection เป็นการฝัง Connection String ไปในตัวรายงาน ดังรูปที่ 4

                3-5

           รูปที่4 Embedded Connection Properties

              2. Use Shared Data Sources Connection ซึ่งผู้ใช้จะต้องไปสร้าง Connection String ไว้ก่อน โดยเข้าไปที่หน้าต่าง Solution Explorer คลิกขวาโฟลเดอร์ Shared Data Sources > Add New Data Source ก็จะเข้าสู่หน้าจอสร้าง Connection ดังรูปที่ 4 ข้อดีของการใช้ Shared Data Sources คือเมื่อมีการเปลี่ยน Connection String สามารถเปลี่ยนที่เดียวไม่ต้องไล่เปลี่ยนทีละรายงาน และ Deploy เฉพาะ Shared Data Sources

              3. ไปที่หน้าต่าง Report Data คลิกขวาโฟลเดอร์ Datasets จะปรากฏหน้าต่าง Dataset Properties ดังรูปที่ 5

                3-6

                          รูปที่5 Dataset Properties

    ประกอบด้วย

        – Query เป็นส่วนสร้าง query โดยผู้ใช้สามารถเลือก Dataset, Data Source และประเภทของ query (Text, Table / View, Stored Procedure หรือ Import Query File – *.sql,*.rdl) จากรูปที่ 5 เมื่อกดปุ่ม Query Designer… จะปรากฏหน้าจอดังรูปที่ 6

           3-7

                       รูปที่6 Query Designer

        จากรูปที่ 6 ในหน้าจอประกอบด้วยส่วนหลักๆ 4 ส่วน ได้แก่ Diagram Pane ที่จะแสดง Table / View ซึ่งสามารถ Add / Remove Diagram โดยกดปุ่ม 3-7-1 จะปรากฏหน้าต่างแสดงรายชื่อ Table / View ทั้งหมดในระบบมาให้ผู้ใช้เลือก และผู้ใช้สามารถเชื่อม (Join) หลายๆตารางได้

        – Fields เป็นส่วนแสดงฟิลด์ข้อมูลที่เลือกมา (Select) ซึ่งผู้ใช้สามารถตั้งชื่อ Field Name ได้ ดังรูปที่ 7

           3-7-2

              รูปที่7 Dataset Properties-Fileds

        – Filters เป็นการกรองข้อมูลที่ได้จากการ query อีกที มีประโยชน์ตอนที่ใช้ Shared Dataset ร่วมกันหลายๆรายงาน ดังรูปที่ 8

           3-7-4

             รูปที่8 Dataset Properties-Filters

        – Parameters โปรแกรมจะ Generate ให้ Auto ตอนที่ผู้ใช้เขียนเงื่อนไขในของการ query ตัวอย่างเช่น ในรูปที่ 6 มีเงื่อนไขว่า “WHERE BUDGET_YEAR = :budget_year” (ในกรณีที่ผู้ใช้สร้างตัวแปลจากหน้าต่าง Report Data > Parameters แล้วนั้นจะต้องเลือก “Parameter Value” ให้ถูกต้อง) ดังรูปที่ 9

           3-7-5

          รูปที่9 Dataset Properties-Parameters

    4.  ไปยังหน้าต่าง Toolbox (View > Toolbox) ดังรูปที่ 10

            4

                          รูปที่10 Toolbox

    ตัวอย่าง สร้างตารางเบิกจ่ายประจำปีงบประมาณ

    –  ลาก Table จาก Toolbox ทางซ้ายมือมาวางบนรายงาน ดังรูปที่ 11 คลิกมุมตารางด้านซ้าย จะปรากฏหน้าจอ Tablix Properties ดังรูปที่ 12 จากนั้นเลือก Dataset name กดปุ่ม “OK”

    4-1

                      รูปที่11 Table

    4-2

               รูปที่12 Tablix Properties

    – เลือกฟิลด์ที่ต้องการแสดงมาใส่ใน Table จัดรูปแบบตามที่ต้องการ ดังรูปที่ 13 และกด Preview เพื่อดูข้อมูล จะช่วยให้ผู้ใช้สามารถเรียกรายงานได้ทันที โดยไม่ต้อง Deploy ขึ้น Report Server ถ้ารายงานมีการระบุพารามิเตอร์ จะขึ้นหน้าจอให้กรอกข้อมูลก่อน ดังรูปที่ 14 ซึ่งถ้าหากไม่ได้กำหนดพารามิเตอร์รายงานจะแสดงผลทันที

    4-3

                     รูปที่13 Design

    4-4

                     รูปที่14 Preview

    สำหรับแบบที่ 2 ใช้ Report Wizard เป็นตัวช่วยสร้างรายงาน จะขอกล่าวถึงในตอนถัดไปค่ะ…

     

  • การเขียนโปรแกรม JSP เชื่อมต่อ ORACLE

         JSP หรือชื่อเต็มว่า Java Server Page เป็นภาษาที่ใช้ในการพัฒนา Application ที่ทำงานบนเว็บไซต์ โดยรูปแบบการทำงานจะทำงานคล้ายกับภาษา  ASP ,PHP และ .Net รูปแบบการทำงานจะแตกต่างกันตรงที่ JSP เป็น Subset ของภาษา Java โดยรูปแบบการเขียนนั้นจะใช้รูปแบบคำสั่งและชุด SDK ของ Java และใน JSP จะมีนามสกุลของไฟล์เป็น .jsp โดยการทำงานจะทำงานในรูปแบบของ Server และ Client แสดงผลและโต้ตอบกับ User Interface ผ่าน Web Browser เช่น  IE ,Chrome ,Firefox และอื่นๆ โดยจะสามารถทำงานร่วมกับ Client Tags เช่นพวก HTML / JavaScript / CSS และพวก jQuery ให้ได้ผลลัพธ์ตามที่ต้องการ ที่สำคัญ JSP สามารถใช้งานได้ฟรี และสามารถรองรับได้ทุก Platform ไม่ว่าจะเป็น Windows ,Linux และ iOS รวมทั้ง Software อื่น ๆ

         Oracle เป็น Database ชนิดหนึ่งซึ่งเป็นโปรแกรมที่ใช้ในการจัดการฐานข้อมูล โดยจะทำหน้าที่เป็นตัวกลางคอยติดต่อประสานระหว่างผู้ใช้และฐานข้อมูล ทำให้ผู้ใช้งานสามารถใช้งานฐานข้อมูลได้สะดวกขึ้น เช่น การค้นหาข้มูลต่างๆ ภายในฐานข้อมูลที่ง่ายและสะดวก โดยผู้ใช้ไม่จำเป็นต้องทราบถึงโครงสร้างภายในของฐานข้อมูลก็สามารถเข้าใช้ฐานข้อมูลนั้นได้

         เริ่มต้นในการเขียนโปรแกรมที่นิยมการ connect  oracle ด้วย jsp จะใช้การ connect  ด้วย  JDBC โดยในส่วน ภาษา jsp จะสามารถใช้ packet ของ java ที่จะสามารถ import class ของ JDBC มาใช้งานใน  jsp ได้ทันที โดยไม่จำเป็นต้องเขียน โปรแรกม เพิ่มเติมให้ยุ่งยาก

     

    ขั้นตอนที่ 1 สร้างไฟล์ jsp โดยข้อมูลภายในจะมีsyntax เหมือนกับ HTML แต่ต่างกันที่นามสกุลไฟล์ จะเป็นนามสกุล .jsp

    <HTML>
    <HEAD>
    <TITLE>Simple JSP to Oracle connection Example</TITLE>
    </HEAD>
    <BODY>
    </BODY>
    <HTML>
    

    ขั้นตอนที่ 2 ทำการ import library ที่ใช้ในการเชื่อมต่อกับ database oracle ด้วย java.sql.*

    <%@ page import="java.sql.*" %>
    
    <HTML>
    <HEAD>
    <TITLE>Simple JSP to Oracle connection Example</TITLE>
    </HEAD>
    <BODY>
    </BODY>
    <HTML>
    

    ขั้นต้อนที่ 3 สร้างตัวแปลที่ใช้ในการเขื่อมต่อ

    String strdrive ="oracle.jdbc.OracleDriver";   //driver ของ oracle
    String url = "jdbc:oracle:thin:@localhost:1521:xe";  //server database
    String usr = "username";  //user name
    String pwd = "pwd";     //password 

    ขั้นต้อนที่ 4 สร้าง connection การเชื่อมต่อไปยัง database

    Connection conn = null;

    ขั้นตอนที่ 5 ทำการเชื่อมต่อกับ database โดยใช้ ตัวแปลจากข้างต้น

    <%
        Connection conn = null;
        try
        {
            Class.forName(strdrive );
            conn = DriverManager.getConnection(url, usr, pwd);
            out.println("connected....!!");
    
        }
    
        catch(Exception e)
        {
            out.println("Exception : " + e.getMessage() + "");
        }
    
    
    %>

    ขั้นตอนที่6 ต้องสร้างตัวแปลเพื่อใช้ในการประมวลผล

    Statement st; // ใช้ในการรับคำสัง sql
    ResultSet rs;  //เก็บข้อมูลที่ได้ขาการประมวลผล
    

    ขั้นตอนที่ 7 ทดสอบการทำงาน

    String SQL="select T1 from table";
    rs=st.executeQuery(SQL);
           while(rs.next())
           {
              out.println("number is: "+rs.getString(1));%>          
           } 

     

  • ASP.NET Core Part I

    asp.net core คือ cross-platform framework สำหรับการพัฒนา web application ที่ทำงานบน .net core หรือ  full .net framework เดิม ( .net core สามารถใช้งานได้ทั้ง Windows , Linux และ MacOS โดยที่ส่วนประกอบต่างๆของ .net core ไม่ว่าจะเป็น runtime, libraries, compiler, language และเครื่องมือต่างๆ เป็น open source ทั้งหมด )  ซึ่ง asp.net core ได้รับการออกแบบใหม่ให้มีประสิทธิภาพดีกว่า asp.net เดิมโดยแบ่งส่วนต่างๆออกเป็น module ย่อยเพื่อลด overhead ในการเริ่มต้นทำงาน ซึ่ง asp.net core ประกอบไปด้วยกลุ่มของ NuGet package แทนที่การใช้งาน System.Web.dll ใน asp.net เดิม ซึ่งผู้พัฒนาสามารถเลือกเฉพาะ package ที่ต้องใช้งานเท่านั้น ทำให้ application มีขนาดเล็กลง มีประสิทธิภาพเพิ่มขึ้น,การพัฒนา Web UI และ Web API จะใช้ libraries เดียวกัน, สนับสนุนการใช้งาน dependency injection, web application สามารถใช้งานบน IIS หรือ self-host ภายใต้ process ของตัวเอง

    ในการพัฒนา asp.net core เราสามารถใช้เครื่องมือที่เป็น text editor ธรรมดาหรือจะใช้เครื่องมือช่วยในการพัฒนาอย่างเช่น Visual Studio ก็ได้ ในส่วนของโครงสร้างของ project asp.net core จะเปลี่ยนไปจากเดิม โดยการกำหนดค่า config ของ project สามารถกำหนดได้ที่ project.json

    {
     "title": "asp.net.core",
     "version": "1.0.0",
    
     "dependencies": {
       "NETStandard.Library": "1.6.0",
       "Newtonsoft.Json": "9.0.1"
     },
    
     "frameworks": {
       "netstandard1.6": {
          "imports": "dnxcore50"
        }
      }
    }

    การ reference ไปยัง NuGet package ที่ต้องการใช้งานใน project สามารถกำหนดได้ใน project.json โดยพิมพ์ชื่อ NuGet package ที่ต้องการพร้อมทั้งระบุ vesrion ในส่วน “dependencies” ซึ่งเมื่อทำการบันทึก project.json เครื่องมืออย่างเช่น visual studio จะทำการ restroe NuGet package ให้กับ project โดยอัตโนมัติ

    asp.net core ได้รับการออกแบบให้รองรับ client-side framework ต่างๆเช่น AngularJS หรือ bootstrap โดยใช้เครื่องมือที่เป็น package manager ในติดตั้ง client-side package ที่ต้องการใช้งาน อย่างเช่น Bower ที่จะกำหนด package ที่ต้องการใช้งานใน bower.json

    {
     "name": "asp.net",
     "private": true,
     "dependencies": {
       "bootstrap": "3.3.6",
       "jquery": "2.2.0",
       "jquery-validation": "1.14.0",
       "jquery-validation-unobtrusive": "3.2.6"
     }
    }

    หรือ npm ที่จะกำหนด package ที่ต้องการใช้งานใน package.json

    {
     "name": "asp.net",
     "version": "1.0.0",
     "private": true,
     "devDependencies": {
       "gulp": "3.8.11",
       "gulp-concat": "2.5.2",
       "gulp-cssmin": "0.1.7",
       "gulp-uglify": "1.2.0",
       "rimraf": "2.2.8",
       "typings": "1.0.5"
     },
     "dependencies": {
       "core-js": "^2.4.0",
       "reflect-metadata": "^0.1.3",
       "rxjs": "5.0.0-beta.6",
       "systemjs": "0.19.27",
       "zone.js": "^0.6.12"
     }
    }

    โดยเมื่อทำการบันทึก package manager จะทำการ restore package ที่ระบุ (bower.json หรือ package.json) ให้กับ project โดยอัตโนมัติ โดยที่ Bower จะติดตั้งลงใน /wwwroot/lib ในขณะที่ npm จะติดตั้งลงไปที่ folder /node_modules

    ในส่วนของ web root ของ asp.net core project จะอยู่ที่ folder /wwwroot ซึ่งต่างจาก asp.net เดิมที่ใช้ root folder ของ project เป็น web root โดยที่ /wwwroot จะเป็น folder ที่เก็บพวก static resources ต่างๆเช่น css, js และ image files

    entry point สำหรับ asp.net core application จะอยู่ที่ class “Startup” ซึ่งจะเป็น class ที่ใช้ในการกำหนด configuration และ service ต่างๆที่จะใช้ใน application โดย asp.net จะทำการค้นหา class ที่มีชื่อ startup ใน primary assembly (ในทุก namespace และไม่สนใจว่า class Startup จะเป็น public class หรือไม่ก็ตาม) ใน class Startup จะต้องมี method “Configure” ซึ่ง asp.net จะเรียกใช้งานตอนเริ่มต้น application (สำหรับ method “ConfigureServices” จะมีหรือไม่ก็ได้)

    สำหรับ Configure method จะต้องรับ parameter type “IApplicationBuilder” และอาจจะระบุ service ที่ต้องการใช้งานเช่น IHostingEnvironment และ ILoggerFactory ซึ่ง service เหล่านี้จะถูก inject โดย server โดยอัตโนมัติ

    IApplicationBuilder ถูกใช้ในการสร้าง application request pipeline ซึ่งสามารถเข้าถึงได้ผ่านทาง Configure method ใน Startup เท่านั้น

    IHostingEnvironment จะใช้เพื่อเข้าถึงข้อมูลสภาพแวดล้อมของ application เช่น EnvironmentName, ContentRootPath, WebRootPath และ web root file provider

    ILoggerFactory ให้ความสามารถในการทำ logging ซึ่งสามารถเข้าถึงได้ผ่านทาง Startup constructor และ Configure method ใน Startup เท่านั้น

     public void Configure(IApplicationBuilder app, 
                           IHostingEnvironment env,
                           ILoggerFactory loggerFactory)
     {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();
    
        if (env.IsDevelopment())
        {
          app.UseDeveloperExceptionPage();
          app.UseDatabaseErrorPage();
          app.UseBrowserLink();
        }
        else
        {
          app.UseExceptionHandler("/Home/Error");
        }
    
        app.UseStaticFiles();
    
        app.UseMvc(routes =>
        {
           routes.MapRoute(
           name: "default",
           template: "{controller=Home}/{action=Index}/{id?}");
         });
    }

    จะเห็นว่ามีการใช้ “Use” extension method เพื่อเพิ่ม middleware เข้าไปสู่ request pipeline ของ asp.net ตัวอย่างเช่น “UseMvc” extension method จะเป็นการเพิ่ม routing middleware เข้าไปสู่ request pipeline

    ใน part I นี้ได้กล่าวถึงส่วนหลักๆของ asp.net core (asp.net 5)  ที่เปลี่ยนไปจาก asp.net เดิม ทั้งในส่วนของ framework และการรองรับการพัฒนา client-side ในส่วนต่อไปเราจะเริ่มต้นพัฒนา asp.net core โดยการสร้าง asp.net core web application project ในแบบง่ายๆ

    อ้างอิง : https://docs.asp.net

  • การสร้างแผนที่ออนไลน์ (Web Map) ด้วยลิงค์ KML/KMZ

    นักพัฒนาเว็บหลายคนคงจะคุ้นเคยกับการสร้าง web map ด้วย google map api กันนะคับ (เป็นที่นิยมเลยล่ะ) แต่ในยุคปัจจุบันที่มีการเผยแพร่ข้อมูลที่เป็น near real time กันมากยิ่งขึ้น จะเห็นได้จากหลายหน่วยงานมีการเผยแพร่ Web Map Services กันเยอะมากยิ่งขึ้น และแย่งชิงความเป็นผู้นำในการนำเสนอข้อมูลที่เป็นปัจจุบันทันด่วนที่สุด

    แต่ด้วยปัจจัยในการต้องติดตั้งโปรแกรมบน Web Map Server เพื่อให้สามารถใช้งาน web map ผ่าน server ได้ (เสียงบประมาณเพิ่ม)
    ***ใครมี ArcGIS Server จะลองทำ การสร้างเว็บแผนที่จุดความร้อน(Hotspot) โดยใช้ WMS บน ArcGIS Server ดูได้นะคับ

     

    วันนี้เลยจะขอนำเสนอโค้ดง่ายๆ ในการนำลิงค์ KML/KMZ จากเว็บที่ให้บริการฟรี! มาสร้างเป็นหน้าเว็บเพจของเราโดยที่ไม่ต้องติดตั้ง map server กันคับ ^^ ที่สำคัญ ต้นทางข้อมูลอัพเดทข้อมูล หน้าเว็บเราก็อัพเดทไปด้วย อิอิ

    ขั้นตอนการสร้าง

    1. เปิดหน้าเว็บที่ให้บริการลิงค์ ***ตัวอย่างเว็บ http://slb-gis.envi.psu.ac.th

    2. เลือกชั้นข้อมูลที่ต้องการ แล้วคลิกขวา > copy link address

    00

    3. สร้างไฟล์ gmap.html แล้วเปิด edit ด้วยโปรแกรม notepad หรือ text editor

    4. copy โค้ดนี้ไปวาง

    <!DOCTYPE html>
    <html>
    <head>
    <meta name=”viewport” content=”initial-scale=1.0″>
    <meta charset=”utf-8″>
    <title>การสร้างแผนที่ออนไลน์ (Web Map) ด้วยลิงค์ KML/KMZ</title>
    <style>
    html, body {
    height: 100%;
    margin: 0;
    padding: 0;
    }
    #map {
    height: 100%;
    }
    </style>
    </head>
    <body>
    <div id=”map”></div>
    <script>

    function initMap() {
    var map = new google.maps.Map(document.getElementById(‘map’), {
    zoom: 11,
    center: {lat: 100.756297, lng: 14.790059}
    });

    var ctaLayer = new google.maps.KmlLayer({
    url: ‘ที่อยู่ kml/kmz ลิงค์‘,
    map: map
    });
    }

    </script>
    <script async defer
    src=”https://maps.googleapis.com/maps/api/js?key=google map api key“>
    </script>
    </body>
    </html>

    4. วางลิงค์ที่ copy มาจากเว็บตรงurl: ‘http://slb-gis.envi.psu.ac.th/home1/images/download/kmz/gcs_slbforu.kmz‘,

    และใส่ google map api key ***ถ้าไม่มีให้ไปที่ https://developers.google.com/maps/documentation/javascript/get-api-key

    01

    5. ลองเปิดผ่าน http://localhost/gmap.html จะได้ตามรูป

    02

    6. หากคลิกที่ข้อมูล จะมี pop-up แสดงข้อมูลขึ้นมา

    03

    7. เว็บไซต์ของท่านก็จะมีหน้าเว็บแมพไว้ใช้งานได้แบบง่ายๆ โดยไม่ต้องติดตั้ง web map server ^^

     

    ****บริการฟรี! ชั้นข้อมูลลุ่มน้ำทะเลสาบสงขลาเพิ่มเติมได้ที่ โครงการการพัฒนาฐานข้อมูลสารสนเทศภูมิศาสตร์ลุ่มน้ำทะเลสาบสงขลา โดย สถานวิจัยสารสนเทศภูมิศาสตร์ทรัพยากรธรรมชาติและสิ่งแวดล้อม คณะการจัดการสิ่งแวดล้อม มหาวิทยาลัยสงขลานครินทร์