Category: Developer

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

  • ตอนที่ 2 : จัดการรายงานด้วย Report Manager

    การใช้งาน Report Manager มีขั้นตอนดังต่อไปนี้

    1. เปิด Browser และพิมพ์ URL ของ Report Server ในช่อง Address โดย URL มีรูปแบบดังนี้ http://<report_server_name>/Reports 
    2. จะปรากฏ หน้าต่าง Windows Security ขึ้นมา เพื่อให้กรอก User name และ Password ในการยืนยันตัวตนเข้าสู่ระบบ
    3. หากการยืนยันตัวตนเข้าสู่ระบบถูกต้องแล้ว ก็จะสามารถเข้าสู่หน้า Home ของ Report Manager (ดูภาพประกอบที่ 1) แสดง Contents ที่ประกอบด้วย

    Home

    ภาพประกอบที่ 1 Home ของ Report Manager

          3.1 เมนูด้านบนขวาที่ใช้ตั้งค่าคุณสมบัติต่างๆ ของ Report Server ดังนี้

                » Home เป็นลิงค์ที่เชื่อมโยงไปยังหน้าหลักของ Report Server ซึ่งก็คือหน้า Home นั่นเอง ประกอบด้วยเมนู ดังนี้

    New Folder เพื่อสร้างโฟลเดอร์ไว้สำหรับเก็บรวบรวมรายงาน, Data Source, Data Model และอื่นๆ ที่มีอยู่ก่อนแล้วไว้ภายใน Folder ที่สร้างขึ้นใหม่

    New Data Source เป็นการสร้าง Data Source ขึ้นมาใหม่เพื่อใช้สำหรับเป็นแหล่งข้อมูลของการสร้างรายงาน

    Report Builder เป็นการใช้โปรแกรม Report Builder แบบ Click Launch โดย User สร้าง Ad hoc Report (โดยการอาศัย Data Model ที่ได้สร้างไว้บน Report Server นำมาใช้เป็นแหล่งข้อมูลในการสร้างรายงาน)

    Folder Settings เพื่อกำหนดบทบาทในการเข้าถึงโฟลเดอร์

    Upload File เพื่อ Upload ไฟล์ต่างๆ เช่น Report (.rdl), Model (.smdl), Shared Dataset (.rsd), Report Part (.rsc) หรือ Resource อื่นๆ มายัง Home ของ Report Server

    Layout  อยู่ด้านขวาสุดของเมนู เป็นมุมมองในการแสดงข้อมูล ซึ่งมี 2 โหมด คือ  Details View และ  Tile View

              เมื่อคลิก Dropdown ที่โฟลเดอร์จะมีเมนู เช่น Move, Delete, Security, Manage และเมื่อคลิก Dropdown ที่รายงานจะมีเมนู เช่น Move, Delete, Subscribe…, Create Linked Report, View Report History, Security, Manage, Download และ Edit in Report Builder (ดูภาพประกอบที่ 3) ซึ่งหากคลิกที่ชื่อรายงานจะไปยังหน้าจอสำหรับเรียกดูรายงาน โดยผู้ใช้สามารถ Export ไฟล์ในรูปแบบต่างๆที่ SSRS Support ดังที่ได้กล่าวเอาไว้ในตอนที่ 1 และกด Print เพื่อพิมพ์รายงาน (ดูภาพประกอบที่ 4)

    Menu Report

    ภาพประกอบที่ 3 เมนูของรายงาน

    Sale_Order

    ภาพประกอบที่ 4 View Report

                » My Subscriptions เป็นลิงค์ที่เชื่อมโยงไปยังหน้าที่แสดงการตั้ง Subscriptions ทั้งหมดของ Report Server กล่าวคือ เป็นหน้าจอที่แสดงรายการที่ผู้ใช้ได้ตั้ง Schedule สำหรับ Run รายงานเอาไว้ (ดูภาพประกอบที่ 5)

    Subscriptions ของ Report Manager

    ภาพประกอบที่ 5 Subscriptions ของ Report Manager

                » Site Setting เป็นลิงค์ที่เชื่อมโยงไปยังหน้าการตั้งค่าหน้าเว็บ Report Manager ซึ่งมี 3 ส่วน คือ

                   − General เป็นการตั้งค่า Properties ต่างๆ เช่น ชื่อ, การเก็บ History, เวลา Timeout และ Custom URL สำหรับ Report Builder (ดูภาพประกอบที่ 6)

    General - Site Settings ของ Report Manager

    ภาพประกอบที่ 6 General – Site Setting ของ Report Manager

                   − Security เป็นการกำนดบทบาท (Role) ในการเข้าถึงหน้าเว็บ Report Manager (ดูภาพประกอบที่ 7) ประกอบด้วย

                          • System Administrator สามารถดู และแก้ไขข้อมูลการตั้งค่าได้

                          • System User สามารถดูข้อมูลได้อย่างเดียว

    Security - Site Settings ของ Report Manager

    ภาพประกอบที่ 7 Security – Site Setting ของ Report Manager

                   − Schedules ป็นการกำนดตารางเวลาที่สามารถใช้ร่วมกัน โดยตอน Create Subscriptions เลือก shared schedules (ดูภาพประกอบที่ 8)

    Schedules - Site Settings ของ Report Manager

    ภาพประกอบที่ 8 Schedules – Site Setting ของ Report Manager

                » Help เป็นลิงค์ที่เชื่อมโยงไปสู่หน้า Report Manager Help ที่จะให้คำแนะนำหากเกิดการตั้งค่า หรือการทำงานที่ผิดพลาด

  • ตอนที่ 1 : มารู้จัก SSRS กันเถอะ…

              SQL Server Reporting Services (SSRS) เป็น Technology หนึ่งของ Microsoft SQL Server Services ที่ใช้ในการสร้างและบริหารจัดการรายงาน เริ่มมีใน SQL Server 2005 และในปัจจุบันเป็น SQL Server 2016 ซึ่งข้อดีของการใช้ SSRS อาทิเช่น ไฟล์รายงานเป็นภาษา Rdl ที่เป็น Text File ธรรมดาสามารถเปิดด้วย Text Editor อะไรก็ได้ (ดูภาพประกอบที่ 1) อีกทั้ง SSRS แถมฟรีมากับ SQL Server ดังนั้นหากมี License การใช้งาน SQL Server ก็จะสามารถใช้ SSRS ทำรายงานได้โดยไม่มีค่าใช้จ่ายอื่นเพิ่มเติม และเมื่อมีการ Deployed รายงานไปแล้ว รายงานจะอยู่ใน Web Server ซึ่งผู้ใช้สามารถเรียกดูรายงานผ่าน Web Browser ได้ (ดูภาพประกอบที่ 2) โดยจะต้องกำหนดสิทธิการเช้าถึง Site และสิทธิการเข้าถึงรายงาน นอกจากนั้นยังสามารถนำรายงานไปฝังตัวไว้เป็นส่วนหนึ่งของ Application ก็ได้ เป็นต้น

    1_1

    ภาพประกอบที่ 1 เปิดไฟล์ *.rdl ด้วย Notepad

    1_2

    ภาพประกอบที่ 2 เรียกดูรายงานผ่าน Web Browser

              SSRS มีสถาปัตยกรรมแบบ Multi-Tier สนับสนุนการใช้งานทั้ง Native Mode และ SharePoint mode ในที่นี้จะขอกล่าวถึงสถาปัตยกรรมของSSRSที่เป็น Native Mode ซึ่งประกอบด้วย Components ต่างๆ ดังนี้ (ดูภาพประกอบที่ 3)

    1. Report Processor เป็นตัวที่ควบคุมการทำงานทั้งหมดที่อยู่ใน Report Server ตั้งแต่ Data Processing จนถึง Authentication โดยการทำงานบางอย่างจะแสดงผลผ่าน Programmatic Interfaces
    2. Programmatic Interfaces เป็นโปรแกรมที่ทำหน้าที่รับการติดต่อการทำงานจากผู้ใช้ แสดงผลการทำงานของรายงาน และ Report Server ให้ผู้ใช้เห็น โดยจะมีการทำงานรวมทั้งนำรายงานจาก Report Server Database มาแสดงผลให้เห็นด้วย
    3. Data Processing เป็นการประมวลผลข้อมูลที่มาจาก Data Source เพื่อนำมาสร้างรายงาน โดยถูกควบคุมการประมวลผลโดย Report processor
    4. Rendering เป็นการแสดงผลรายงาน ก่อนที่จะทำการส่งไปให้ผู้ใช้หรือสั่งพิมพ์นำไปใช้งาน
    5. Report Processing เป็นการประมวลผลรายงาน โดยจะรับข้อมูลที่ถูกส่งต่อมาจาก Data Processing มาประมวลผล
    6. Authentication (Security) เป็นการยืนยันตัวตนของผู้ใช้ที่ต้องการใช้งาน Report Server โดยแสดงหน้าจอในการ Log on เข้าใช้งาน ผ่าน Programmatic interfaces หาก Log on สำเร็จผู้ใช้ก็จะสามารถเข้าใช้งานได้
    7. Scheduling and Delivery Processor เป็นตัวประมวลผลการตั้งเวลาและการส่งรายงาน ทำหน้าที่ควบคุม การส่งรายงาน จะมีการให้ผู้ใช้ที่มีสิทธิ์ได้ตั้งเวลาและทำการกำหนดการส่งรายงานให้กับเป้าหมายโดยผ่าน Programmatic interfaces
    8. Delivery เป็นการส่งรายงานให้กับผู้ใช้ที่เป็นเป้าหมาย

     

    1_3

    ภาพประกอบที่ 3 SSRS components

    ที่มา : https://msdn.microsoft.com/en-us/library/ms157231.aspx

     

    ความสามารถในการ Authoring SSRS 

    1. สร้างรายงานได้จากหลายแหล่งข้อมูล (Data Sources) ที่มีอยู่ เช่น SQL Server, Oracle, OLE DB, OLEDB-MD, ODBC, XML, SAP BI NetWeaver, Hyperion Essbase, Teradata, Microsoft SQL Azure (SQL in the Cloud), Microsoft SQL Server Parallel Data Warehouse, Microsoft SharePoint List เป็นต้น
    2. สามารถกำหนดสิทธิให้ผู้ใช้สร้างรายงานได้เอง ผ่านโปรแกรม SQL Server Report Builder
    3. สามารถใช้ Expression ในการแสดงข้อมูล ซึ่งมีหลายประเภทให้ใช้งานตามความต้องการ (ดูภาพประกอบที่ 4)
    4. สามารถจัดกลุ่มข้อมูล (Grouping), การเรียงข้อมูล (Sorting) และ การกรองข้อมูล (Filtering) รวมถึงสร้างตัวแปร, เขียนฟังก์ชั่นประมวลผลข้อมูล
    5. Layout, Table, Matrix ของรายงานมีความยืดหยุ่น
    6. นำเสนอข้อมูลที่ซับซ้อนให้ผู้ใช้รายงานเข้าใจได้ง่าย ด้วยการแสดงข้อมูลแบบ Graphic ที่แสดงภาพรวมของการสรุปข้อมูลโดยใช้ Chart หรือ Gauge
    7. สามารถ Export ไฟล์ ในรูปแบบต่างๆ XML (File With Report Data), CSV (Comma Delimited), Tiff File, Pdf, Mhtml (Web Archive), Excel และ Word เป็นต้น

    1_4

    ภาพประกอบที่ 4 Expression

    อ้างอิง:

    เคล็ดลับการทำรายงานจากฐานข้อมูล

  • ASP.NET MVC Part3: สร้าง Model ด้วย Entity Framework

    จากบทความก่อนหน้า ซึ่งอาจจะนานมากพอสมควรที่ได้แนะนำ MVC ไปไว้แล้วในเบื้องต้น (ASP.NET MVC Part 1 : ทำความรู้จักกับ ASP.NET MVC และ ASP.NET MVC Part2: เริ่มต้นสร้างเว็บด้วย MVC with Bootstrap) บทความนี้จะมาแนะนำในส่วนของการสร้าง Model ในการเชื่อมต่อกับฐานข้อมูล ในการ query และจัดการกับข้อมูล เพื่อส่งให้กับ Controller และ View เรียกใช้ในลำดับต่อไป

    Model คือ ส่วนหนึ่งในองค์ประกอบของการพัฒนาเว็บแอพพลิเคชันตามรูปแบบ MVC Framework (Model-View-Controller) โดยจะเป็นส่วนที่ทำหน้าที่ Business Model หรือส่วนที่ติดต่อกับฐานข้อมูล โดยบทความนี้นำเสนอการนำเครื่องมือ Entity Framework มาใช้ในการสร้างและจัดการ Model ในการเชื่อมต่อกับฐานข้อมูล สำหรับการพัฒนาเว็บแอพพลิเคชันตามรูปแบบ MVC Framework

    Entity Framework
    Entity Framework คือ tools ที่ทำหน้าที่จัดการกับฐานข้อมูล โดยแนวคิดของ Entity Framework อยู่ในรูปแบบของ O/RM (Object/Relational Mapping) คือ Entity Framework จะสร้าง Layer ทำหน้าที่เป็น Database Model ขึ้นมาเป็น Class ใน Project ของเรา โดยจะทำหน้าที่ Mapping ตัว Class ที่จะสร้างขึ้น กับ Table , View และ Stored Procedure จากฐานข้อมูบ มาไว้บน Project ซึ่งทำให้เราเราสามารถเรียกใช้มันผ่าน Class ที่อยู่ใน Project เราได้เลย ส่วนการเขียน Query หรือจัดการกับข้อมูลผ่านตัว Entity Model จะใช้ Syntax ของ LINQ to Entities ซึ่งเป็น syntax ที่สามารถเข้าใจได้ง่ายตามรูปแบบของภาษาเช่น VB.Net หรือ C#

    ex_entity
    ตัวอย่างการใช้งาน Entity Framework

     

    วิธีการใช้งาน Entity Framework เบื้องต้น

    1. เปิด solution ที่ต้องการใช้ขึ้นมา (ในบทความนี้เป็น project แบบ MVC Framework)

    2. คลิกขวาที่โฟลเดอร์ Model แล้วเลือก Add =>New Item

    3. ที่ tab ด้านซ้ายมือ เลือก Data จากนั้นเลือก ADO.NET Entity Data Model และทำการตั้งชื่อ และกดปุ่ม Add

    new_entityModel

     

    4. เมื่อเข้าสู่หน้าจอให้เลือก Model Content ให้เลือก EF Desiner from DataBase และกด Next จะเข้าสู่ขั้นตอนต่อไป

    choose_content

     

    5.ขั้นตอนถัดมาคือการเลือก Data Connection เป็นการเลือกการติดต่อกับฐานข้อมูลว่าจะให้ Entity ติดต่อกับฐานข้อมูลไหน โดยครั้งแรกหากยังไม่มี ฐานข้อมูลมาให้เลือกใน comboBox จะต้อง New Connection ขึ้นมาก่อน และทำตามขั้นตอนไปได้เลย แต่ถ้ามีแล้วให้เลือก Connection จาก ComboBox หลังจากนั้นให้กดเลือก Yes,include the sensitive data in connection string และเลือก Checkbox ให้ Save Connection string เข้าสู่ Web.Config และตั้งชื่อให้กับ Conection string โดย default ชื่อจะเป็น “Entities” และกดปุ่ม Next เข้าสู่ขั้นตอนต่อไปchoose_dataConrection

     

    6.ขั้นตอนนี้เป็นขั้นตอนสุดท้าย สำหรับเลือกว่า เราจะติดต่อ Entity กับ Table, View หรือ Storeprocdure อะไรบ้าง ให้กด expand และเลือก Table, View หรือ Storeprocdure ที่ต้องการ หลังจากนั้นให้กดปุ่ม Finish เป็นอันเสร็จกระบวนการสร้าง Entity Data Model ในการติดต่อกับฐานข้อมูล

    choose_table

     

    การเรียกใช้งานจากฝั่ง Controller

    1.ที่ไฟล์ xxxController.cs ทำการ using เพื่อเรียกใช้งาน

    using MVCBootstrap.Models;
    

    2.ประกาศตัวแปรขึ้นมา new object เพื่อจะเข้าถึง entity model ที่เราได้ทำการสร้างไว้ก่อนหน้านี้

    var db = new Budget_Entities();
    

    3.เข้าถึงแต่ละ Entity โดยใช้ syntax linq  โดยขอยกตัวอย่างในส่วนของการเข้าถึงและจัดการข้อมูลเบื้องต้น

    • Query ข้อมูล
     public ActionResult QueryData()
            {
                var db = new Budget_Entities();
                var listCampus = db.VF_CAMPUS.Where(w => w.CAMP_NAME_THAI.Contains("วิทย"));
                return View(listCampus);
            }
    
    • Insert ข้อมูล

    public ActionResult InsertData()
            {
                bool isSuccess = true;
                I_ITEM item = new I_ITEM();
                item.ITEM_NO = "001";
                item.ITEM_THAI_NAME = "รายการวัสดุทางการศึกษา";
                db.SaveChanges();
                return View(isSuccess);
            }
    
    • Update ข้อมูล

     public ActionResult UpdateData(int itemID)
            {
                bool isSuccess = true;
                var db = new Budget_Entities();
                var itemForUpdate = db.I_ITEM.Find(itemID);
                itemForUpdate.ITEM_THAI_NAME = "รายการวัสดุแก้ไข";
                db.SaveChanges();
                return View(isSuccess);
            }
    
    • Remove ข้อมูล
     public ActionResult RemoveData(int itemID)
            {
                bool isSuccess = true;
                var db = new Budget_Entities();
                var itemForRemove = db.I_ITEM.Find(itemID);
                db.I_ITEM.Remove(itemForRemove);
                db.SaveChanges();
                return View(isSuccess);
            }
    

     

    ซึ่งจากทั้ง 4 ตัวอย่างจะมีการประกาศตัวแปร var db = new Budget_Entities(); เป็นการ new object ขึ้นมาเพื่อที่จะเข้าถึง entity ภายใน และทำการ query ข้อมูล, set ค่าให้กับ attribute หรือลบข้อมูล หลังจากที่จัดการกับตัว entity เสร็จแล้ว จะเรียกใช้งาน method SaveChanged() ซึ่งเป็นการสั่งให้ entity Model ทำการ execute และเปลี่ยนแปลงข้อมูลตามที่เราได้เขียน code ไว้ไปยังฐานข้อมูล เป็นอันเสร็จกระบวนการในการเปลี่ยนแปลงข้อมูลที่กระทำกับฐานข้อมูล จากนั้นเราจะเอาค่านั้นไปใช้ต่อหรือ จะ return ค่า ไปยัง View เพื่อแสดงผลต่อไปก็แล้วแต่ผู้ใช้เลยค่ะ

     

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

    บทความก่อนหน้า : ASP.NET MVC Part2: เริ่มต้นสร้างเว็บด้วย MVC with Bootstrap

    แหล่งข้อมูลอ้างอิง :

    [1] http://www.asp.net/mvc/overview/getting-started/database-first-development/creating-the-web-application

    [2] https://msdn.microsoft.com/en-us/library/bb399760(v=vs.100).aspx

  • การเรียกใช้งานเมธอดในฝั่งเซิร์ฟเวอร์/เว็บเซอร์วิสแบบ Ajax ด้วย jQuery (C#)

              ก่อนจะพูดถึงวิธีการเรียกใช้งานเมธอดในฝั่งเซิร์ฟเวอร์/เว็บเซอร์วิสแบบ Ajax ด้วย jQuery ผู้เขียนขอเกริ่นนำเกี่ยวกับที่มาที่ไปเกี่ยวกับแนวคิดแบบ Ajax เพื่อให้ผู้อ่านบางท่านที่ยังอาจงงๆได้ทำความเข้าใจเสียก่อน ว่าโดยปกติแล้วนั้น ในการพัฒนาเว็บไซต์(Web application)ของ ASP.NET จะประกอบด้วย 2 ส่วน คือ Client side และ Server side ซึ่งการทำงานในส่วนของ Client side จะหมายถึงส่วนของ browser หรือหน้าจอการทำงานของผู้ใช้ เช่น Google Chrome Firefox และ Internet explorer ส่วนในฝั่งเซิร์ฟเวอร์จะมีการรับคำร้องขอ(request) จากฝั่ง Client ทำการประมวลผลและส่งค่าผลลัพธ์คืนกลับมายังฝั่ง Client อีกครั้งเพื่อให้ผู้ใช้เห็นผลลัพธ์การตอบกลับนั้นได้ ซึ่งโดยปกติแล้วนั้นการพัฒนาจะประกอบด้วยโค้ด 2 ส่วน คือ

    • Server-side code ซึ่งเป็นเทคโนโลยีของการทำงานในการติดต่อไปยังฝั่งเซิร์ฟเวอร์ และถูกนำมาใช้ในการพัฒนา Web application ซึ่งใน ASP.NET นั้นนับว่าได้รับความนิยมเป็นอย่างมาก โดยจะมีการใช้งานผ่านทาง .NET Framework ในรูปแบบของภาษา C# VB หรือภาษาอื่นๆที่มีใน .NET ในการประมวลผลเพื่อติดต่อกับฐานข้อมูล หรือแหล่งข้อมูลอื่นๆจากคำร้องขอในฝั่ง Client และทำการส่งผลลัพธ์ที่ได้กลับมายังฝั่ง Client อีกครั้ง หลังจากมีการส่งผลลัพธ์ตอบกลับมาเรียบร้อยแล้วนั้น จะมีการ render หน้าจอดังกล่าวขึ้นอีกครั้งเพื่อแสดงผลลัพธ์ที่ได้ ทำให้เพจหรือหน้าจอที่ใช้งานมีการโหลดหรือ refresh เกิดขึ้น ซึ่งอาจส่งผลเสียทำให้ผู้ใช้รู้สึกล่าช้าในการรอการตอบกลับการประมวลผลพร้อมทั้งการแสดงผลจากฝั่งเซิร์ฟเวอร์ โดยโค้ดในลักษณะนี้ผู้พัฒนาบางท่านอาจรู้จักกันในนามของ code behind นั่นเอง
    • Client-side code อาจเรียกได้ว่าเป็น client-side script ที่ถูกฝังไว้ในฝั่ง client และมีการประมวลผลในส่วนของ Browser ของผู้ใช้ ซึ่งสคริปต์ที่นิยมใช้ในการพัฒนาโดยส่วนใหญ่จะเป็น JavaScript และโต้ตอบกลับมาโดยตรงด้วย element ที่มีใน HTML เช่น textbox ปุ่ม หรือตาราง เป็นต้น นอกจากนี้ยังมีการใช้งานของโค้ดภาษา HTML และ CSS(Cascading Style Sheets) ร่วมด้วย แต่การพัฒนาในส่วนนี้ต้องมีการคำนึงถึงภาษาและโค้ดที่รองรับในแต่ละ browser ของผู้ใช้ด้วย ซึ่งการพัฒนาด้วยโค้ดในส่วนนี้ จะทำให้การตอบโต้กับผู้ใช้งานเกิดขึ้นภายในเวลาอันสั้น เกิด overhead น้อย แต่ก็มีข้อเสียเกี่ยวกับการเลือกใช้ภาษาในการพัฒนาให้ครอบคลุมในความหลากหลายของ browser ที่ผู้ใช้ใช้งานในการเปิดเว็บไซต์ได้

    Ajax (Asynchronous JavaScript and XML)
              เทคโนโลยีและแนวคิดแบบ Ajax ได้เข้ามามีบทบาทในการเปลี่ยนแปลงแนวคิดและหลักการทำงานโดยทั่วไปที่มีอยู่เดิมของ web application เล็กน้อย คือจะมีการส่งคำร้องขอจากฝั่ง Client ไปยังฝั่งเซิร์ฟเวอร์โดยตรงเพื่อตอบโต้กับ object ที่มีในฝั่งเซิร์ฟเวอร์ เช่น ฐานข้อมูล หรือไฟล์ เป็นต้น โดยปราศจากการ postback โดยแนวคิดของ Ajax จะเกี่ยวข้องกับเทคโนโลยีที่มีอยู่เดิม เช่น ข้อมูลในฝั่งเซิร์ฟเวอร์ เว็บเซอร์วิส และการเขียนสคริปต์ในฝั่ง client โดย client-side script จะใช้ในการเรียกใช้เว็บเซอร์วิสเพื่อประมวลผลกับฐานข้อมูลตามคำร้องขอ ซึ่งคำร้องขอดังกล่าวอาจเป็นการบันทึกหรืออ่านค่าข้อมูลจากฐานข้อมูล และการเรียกใช้แบบ Ajax นี้จะเป็นลักษณะ Asynchronous คือ เมื่อผู้ใช้มีการส่งคำร้องขอไปยังเว็บเซอร์วิส ในหน้าจอการทำงานจะไม่ถูกล็อคไว้ และสามารถทำงานในส่วนอื่นต่อได้โดยไม่จำเป็นต้องรอกระบวนการทำงานให้เสร็จทีละส่วน สามารถทำคู่ขนานกันไปได้ และหากส่วนใดเสร็จสิ้นการประมวลผลแล้วนั้นตัวเว็บเซอร์วิสก็จะส่งผลลัพธ์กลับมาให้แสดงยังฝั่งผู้ใช้เอง
              โดยเทคโนโลยีที่ถือว่ามีความสำคัญและจำเป็นสำหรับ client-side script นั่นก็คือ jQuery ที่เรารู้จักกันดี ซึ่งเป็นที่นิยม เนื่องจากประมวลผลได้เร็ว มีขนาดเล็ก และมีคุณสมบัติอีกหลายประการที่จะเข้ามาช่วยทำให้การพัฒนาโปรแกรมมีประสิทธิภาพมากยิ่ง
    จากข้อความข้างต้น แสดงให้เห็นว่าการพัฒนาเว็บไซต์โดยหลีกเลี่ยงการ postback เมื่อมีการเรียกใช้งานไปยังฝั่งเซิร์ฟเวอร์ ถือเป็นอีกทางเลือกของนักพัฒนาที่จะหยิบมาใช้ เพื่อลด over head ให้กับตัว web server และสามารถตอบสนองต่อผู้ใช้ได้รวดเร็วขึ้น ลดจำนวนในการโหลดเพจ และรอการตอบสนองทุกครั้งที่มีการส่งคำร้องขอ ผู้เขียนจึงขอแนะนำวิธีการเรียกใช้หรือส่งคำร้องขอไปยังฝั่งเซิร์ฟเวอร์แบบ Ajax ด้วย jQuery ดังนี้

    • การเรียกใช้เมธอดในฝั่งเซิร์ฟเวอร์ตามแนวคิดของ Ajax ด้วย jQueryหลักการเขียนเพื่อเรียกใช้เมธอดในฝั่งเซิร์ฟเวอร์/เว็บเซอร์วิส
      CheckUserNameAvailability-2
      ที่มาของภาพ :http://www.aspsnippets.com/Articles/Call-ASPNet-Page-Method-using-jQuery-AJAX-Example.aspx
       

      • ตัวอย่างที่ 1 : การเรียกใช้งานเมธอดแบบส่งค่ากลับเป็น string แบบไม่มีการส่งค่าพารามิเตอร์
        ฝั่ง Client(aspx)
       function CallServerMethodString() {
                          $.ajax({
                              type: "POST", //ชนิดในการส่งค่า
                              contentType: "application/json",
                              ///ที่อยู่ของเมธอดที่ต้องการเรียก (ชื่อเพจ/ชื่อเมธอด)
                              url: "TestPageMethod.aspx/getDataRetString", 
                              dataType: "json", ///ส่งค่าแบบ json
                              beforeSend: function () {
                              ///  เป็นส่วนการแสดง loading progress bar ในขณะที่กำลังทำงานอยู่
                                  $("#loadingmessage").show();
                              },
                             //////เป็นส่วนที่เกิดขึ้น เมื่อเกิดข้อผิดพลาดในการเรียกใช้เมธอด
                              error: function (XMLHttpRequest, textStatus, errorThrown) {
                                  alert("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
                              },
                            //////เป็นส่วนที่เกิดขึ้น เมื่อการเรียกใช้เมธอดเสร็จสิ้นสมบูรณ์
                              success: function (response) {
      ///ล้างค่าข้อมูลใน div และนำผลลัพธ์ที่ได้จากการเรียกใช้(response.d) มาแสดงใน div ที่กำหนด
                                  $("#dvResult").html("");
                                  $("#dvResult").append(response.d);
      ///ซ่อน loading progress bar เมื่อเสร็จสิ้นการทำงาน
                                  $("#loadingmessage").hide(); 
                              }
      
                          });
                      }
      

      ฝั่ง Server (c#)

       [System.Web.Services.WebMethod]
       public static string getDataRetString()
       {
           string Result = "";
           string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
           var results = from p in digits
                            select p;
           foreach (var d in digits)
           {
               Result= Result+ "Result is :" + d.ToString() + "<br>";
           }
              return Result;
          }
       }
      

      คำอธิบาย : เป็นตัวอย่างการสร้างเมธอดในฝั่งเซิร์ฟเวอร์ โดยในการสร้างเมธอดต้องมีการกำหนด [System.Web.Services.WebMethod] ไว้ในส่วนบนของเมธอด และมีชนิดเป็น static โดยในส่วนนี้ตามความเป็นจริงจะเป็นส่วนที่อาจมีการดึงมาจากฐานข้อมูล เพื่อคืนค่ากลับไปให้ฝั่ง Client แสดงผล แต่ในที่นี้จะขอสร้างเป็นเพียงข้อมูลสมมุติของอาร์เรย์ที่เป็นข้อความขึ้นมาเท่านั้น

      ผลลัพธ์

      result1

      • ตัวอย่างที่ 2 : แบบส่งค่ากลับเป็น object โดยมีการส่งพารามิเตอร์มายังฝั่งเซิร์ฟเวอร์ด้วย
        ฝั่ง Client (aspx)
      <script type="text/javascript">
       function CallServerMethodObject() {
                          $.ajax({
                              type: "POST",
                              contentType: "application/json",
                              url: "TestPageMethod.aspx/getDataRetObj",
               ///ส่งค่าพารามิเตอร์จากการเลือกประเภทสถานศึกษาให้กับเมธอดฝั่งเซิร์ฟเวอร์
                              data: "{'CategoryID' : " + ddlMain.val() + "}",
                              dataType: "json", ///ส่งค่าแบบ json
              /// เป็นส่วนการแสดง loading progress bar ในขณะที่กำลังทำงานอยู่
                              beforeSend: function () {
                                  $("#loadingmessage").show();
                              }, 
                              error: function (XMLHttpRequest, textStatus, errorThrown) {
                                  alert("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
                              },
              ///เป็นส่วนที่จะทำงานเมื่อมีการเรียกใช้เมธอดเสร็จสิ้นโดยไม่มีข้อผิดพลาดใดๆ
                              success: function (response) {
                  ///ประกาศตัวแปรของคอนโทรล dropdownlist ที่ชื่อว่า ddlResult และล้างค่าข้อมูล
                                  var ddlResult = $("[id*=ddlResult]");
                                  ddlResult.empty().append('กรุณาเลือกชื่อสถานศึกษา');
                   ///วนรอบเพื่อดึงค่าจาก obj ที่ถูกส่งกลับมาเพื่อ populate ลงใน dropdownlist 
                                 $.each(response.d, function (index, item) {
                             ddlResult.append($("").val(item.SubCategory).html(item.title));
                                  });
                   ////ซ่อน loading progress bar เมื่อการทำงานสิ้นสุด
                                $("#loadingmessage").hide();
                              }
                          });
                      }
        </script>
       <asp:DropDownList ID="ddlMain" runat="server" onchange="CallServerMethodObject()" >
       <asp:ListItem Selected="True" Value="0">กรุณาเลือกประเภทสถานศึกษา</asp:ListItem>
       <asp:ListItem Value="1">มหาวิทยาลัย</asp:ListItem>
       <asp:ListItem Value="2">โรงเรียน</asp:ListItem>
       </asp:DropDownList>
       <asp:DropDownList ID="ddlResult" runat="server" >
      <asp:ListItem Value="0">กรุณาเลือกชื่อสถานศึกษา</asp:ListItem>
      </asp:DropDownList>
      

      คำอธิบาย : เป็นตัวอย่างการสร้าง Cascading dropdownlist อย่างง่าย โดยหากมีการเลือกประเภทสถานศึกษา จะมีการเรียกใช้ฟังก์ชั่น CallServerMethodObject() และส่งค่าที่เลือก(รหัสประเภทสถานศึกษา) ให้กับการเรียกใช้เมธอดในฝั่งเซิร์ฟเวอร์ในพารามิเตอร์ที่ชื่อว่า CategoryID เพื่อดึงค่าของชื่อสถานศึกษาตามประเภทที่เลือก

      ฝั่ง server (c#)

       [System.Web.Services.WebMethod]
          public static object getDataRetObj()
          {
      ///สมมุติให้ในส่วนนี้ เป็นการสร้างข้อมูลที่เป็น object และนำผลลัพธ์ที่ได้ส่งกลับไปยั่งฝั่ง Client เพื่อแสดงผล
        var obj = new { Category = 1, SubCategory=1, title = "มหาวิทยาลัยสงขลานครินทร์"};
        var objList = (new[] { obj }).ToList();
        objList.Add(new { Category = 1, SubCategory=2,  title = "มหาวิทยาลัยราชภัฎสงขลา" });
        objList.Add(new { Category = 2, SubCategory=3, title = "โรงเรียนมหาวชิราวุธ"});
        objList.Add(new { Category = 2, SubCategory=4, title = "โรงเรียนหาดใหญ่วิทยาลัย" });
      ////ดึงค่าชื่อสถานศึกษาตามรหัสประเภทสถานศึกษา CategoryID
              var results = from p in objList.Where(p=>p.Category==int.Parse(CategoryID))
                            select p;
      
              return results;
          }

      คำอธิบาย : เป็นตัวอย่างการสร้างเมธอดในฝั่งเซิร์ฟเวอร์ โดยในการสร้างเมธอดต้องมีการกำหนด [System.Web.Services.WebMethod] ไว้ในส่วนบนของเมธอด และมีชนิดเป็น static โดยในส่วนนี้ตามความเป็นจริงจะเป็นส่วนที่อาจมีการดึงมาจากฐานข้อมูลตามเงื่อนไขของพารามิเตอร์ที่ส่งมา เพื่อคืนค่ากลับไปให้ฝั่ง Client แสดงผล แต่ในที่นี้จะขอสร้างเป็นเพียงข้อมูลสมมุติของ object ขึ้นมาเท่านั้น

      ผลลัพธ์

      result3

    • การเรียกใช้เว็บเซอร์วิสตามแนวคิดของ Ajax ด้วย jQuery
      • ตัวอย่างที่ 1 : เป็นการเรียกใช้เมธอดจากเซอร์วิสในการแสดงผล

      ฝั่ง Client(aspx)

     <script type="text/javascript">
     function CallWebservice() {
                        var ddlMain = $("[id*=ddlMain]");
    
                        $.ajax({
                            type: "POST",
                            contentType: "application/json",
                            url: "WebServiceTest.asmx/getDataRetOddEven",
                            ///ส่งค่าพารามิเตอร์จากการเลือกประเภทชนิดข้อมูลตัวเลขให้กับเมธอดที่สร้างในเซอร์วิส
                            data: "{'CategoryID' : " + ddlMain.val() + "}",
                            dataType: "json",
                            beforeSend: function () {
                                $("#loadingmessage").show();
                            }, error: function (XMLHttpRequest, textStatus, errorThrown) {
                                alert("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
                            },
                            success: function (response) {
                                $("#dvResult").html("");
                                $("#dvResult").append(response.d);
                                $("#loadingmessage").hide();
                            }
    
                        });
                    }
     </script>
     <asp:DropDownList ID="ddlMain" runat="server" onchange="CallWebservice()" >
     <asp:ListItem Selected="True" Value="-1">กรุณาเลือกประเภทตัวเลข</asp:ListItem>
     <asp:ListItem Value="0">เลขคู่</asp:ListItem>
     <asp:ListItem Value="1">เลขคี่</asp:ListItem>
     </asp:DropDownList>
    

    คำอธิบาย : เป็นตัวอย่างการเรียกใช้เมธอดจากเว็บเซอร์วิส เพื่อทำการดึงค่าข้อมูลตัวเลขตามประเภทของตัวเลขที่เลือกจาก dropdownlist ซึ่งในตัวอย่างนี้จะเป็นการเรียกใช้เมธอดที่มีชื่อว่า getDataRetOddEven ในเว็บเซอร์วิส WebServiceTest.asmx โดยลักษณะการเรียกใช้จะคล้ายกับตัวอย่างของการเรียกใช้เมธอดจากฝั่งเซิร์ฟเวอร์ที่กล่าวไว้แล้วก่อนหน้านี้ มีเพียงส่วนของการกำหนด url ที่เมธอดนั้นอยู่เท่านั้นที่ต้องให้มาอ้างจากเมธอดในเว็บเซอร์วิสแทน

    ฝั่งเว็บเซอร์วิส (WebServiceTest.asmx)

     [WebMethod]
        public string getDataRetOddEven(string CategoryID)
        {
             string result = "";
             int[] numbers = { 0, 1, 2, 3,4, 5, 6, 7,8, 9 };
    
             var results = from p in numbers.Where(p => p % 2 == int.Parse(CategoryID))
                          select p;
             foreach (var d in results)
             {
                 result = result + "Result is :" + d.ToString() + "
    ";
             }
             return result;
        }
    

    คำอธิบาย : เป็นตัวอย่างการสร้างเมธอดในเว็บเซอร์วิสเพื่อรับค่าชนิดของตัวเลข(คู่/คี่) เพื่อนำมาใช้ในการดึงข้อมูลตามเงื่อนไข โดยในการสร้างเมธอดต้องมีการกำหนด [WebMethod] ไว้ในส่วนบนของเมธอด และมีเพิ่ม [System.Web.Script.Services.ScriptService] ในส่วนบนของไฟล์ เพื่อให้สามารถรันสคริปต์ผ่านเว็บเซอร์วิสได้ โดยในส่วนนี้ตามความเป็นจริงจะเป็นส่วนที่อาจมีการดึงมาจากฐานข้อมูล เพื่อคืนค่ากลับไปให้ฝั่ง Client แสดงผล แต่ในที่นี้จะขอสร้างเป็นเพียงข้อมูลสมมุติของอาร์เรย์ที่เป็นข้อความขึ้นมาเท่านั้น
    หมายเหตุ : 

    ผลลัพธ์

    result4result5

    เพิ่มเติม : 
    Namespace ที่ต้องอ้างอิงเพิ่มเติมหากมีการใช้งานเกี่ยวกับ LINQ คือ using System.Linq;

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

    แหล่งข้อมูลอ้างอิง :
    http://www.seguetech.com/blog/2013/05/01/client-side-server-side-code-difference
    http://www.aspsnippets.com/Articles/Call-ASPNet-Page-Method-using-jQuery-AJAX-Example.aspx

  • สร้างเอกสาร PDF ด้วย iTextSharp

    ที่มา

    บ่อยครั้งที่ในชีวิตของโปรแกรมเมอร์จะต้องพบกับความต้องการของลูกค้าที่อยากได้รายงานหรือเอกสารที่สามารถสร้างได้จากระบบ แน่นอนว่าประเภทเอกสารที่ต้องการย่อมมี PDF บรรจุไว้แน่นอนเพราะเป็นเอกสารที่นิยมใช้กันอย่างแพร่หลาย ทั้งนี้ เครื่องมือสำหรับการสร้างเอกสารประเภทดังกล่าวมีอยู่มากมาย แต่จุดสำคัญนั้นอยู่ที่การเลือกใช้งานซึ่งย่อมแตกต่างกันไปตามปัจจัยต่าง ๆ เช่นในบทความนี้ ลูกค้าต้องการเอกสารเพื่อพิมพ์เป็น hard copy ไว้ที่หน่วยงาน ยังไม่ถึงขั้นรายงานนะครับ แค่เอกสารบันทึกข้อความ ดังนั้นผู้เขียนจึงไม่เลือกใช้เครื่องมือที่เก่งกาจเช่น Crystal report หรือ Reporting service และทำการค้นหาเครื่องมือที่มีน้ำหนักเบา (เวลาใช้ไม่กินทรัพยากรเยอะ) แต่ตอบสนองความต้องการได้ในขณะนั้น รวมไปถึงการมี documentation ที่ดี เข้าใจง่าย ปฏิบัติตามได้ไม่ยาก ซึ่งสุดท้ายก็มาเจอกับเครื่องมือที่ชื่อ iTextSharp

    คุณสมบัติของเครื่องมือ

    iTextSharp เป็นผลงานของ iText ซึ่งทำมาเพื่อการสร้างเอกสาร PDF บน C# platform โดยเฉพาะ ในขณะเดียวกันก็มีเครื่องมือแบบเดียวกันสำหรับ platform อื่น ๆ ด้วย เราจึงจะได้เห็นตัวอย่างใน documentation ของเขาเป็นภาษา Java

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

    การใช้งานเครื่องมือนี้จะต้องใช้การเขียนโปรแกรม 100% ครับหรือเรียกเป็นภาษาอังกฤษว่า Programmatically ซึ่งยุ่งยากพอควรทีเดียวโดยเฉพาะการจัดวางตำแหน่งของแต่ละส่วน พูดได้ว่าจะต้องจินตนาการหรือร่างแบบลงบนกระดาษเลยทีเดียว ทั้งนี้ทั้งนั้นนี่ก็เป็นข้อดีข้อหนึ่งสำหรับคนชอบเขียนโปรแกรมเพราะเห็นกระบวนการชัดเจน (ไม่ค่อยสะดวกแต่สนุกดี)

    ทดลองใช้

    ติดตั้งโปรแกรม

    ก่อนอื่นเลยก็ต้อง download library มาก่อนครับ (Link)การติดตั้งนั้นไม่ยาก แค่ reference ไปหา dll ที่เค้าให้มาก็พอ ไฟล์ที่ได้มามีทั้งหมด 3 ชุดครับคือ

    1. itextsharp-dll-core
    2. itextsharp-dll-pdfa
    3. itextsharp-dll-xtra

    ทั้งหมดนี้ทำหน้าที่แตกต่างกันครับ สำหรับการสร้าง PDF เราใช้แค่ตัว itextsharp-dll-core ก็พอ

    องค์ประกอบพื้นฐาน

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

    1. Chunk เป็นองค์ประกอบสำหรับ “คำ”
    2. Phrase คือ “ประโยค” ซึ่งประกอบด้วยหลาย Chunk
    3. Paragraph คือ “ย่อหน้า” ซึ่งประกอบด้วยหลาย phrase และ chunk
    4. PdfPCell คือ cell ในตาราง
    5. PdfPTable คือ ตารางประกอบด้วยหลาย PdfPCell
    6. iTextSharp.text.Image คือรูปภาพ

    การกำหนด font และการเพิ่ม font

    iTextSharp นั้นสามารถเพิ่ม font ได้ครับ โดยการทำตามขั้นตอนดังนี้:

    BaseFont bf_bold = BaseFont.CreateFont(HttpContext.Current.Server.MapPath(“~/Regist/Theme/fonts/THSarabunNewBold.ttf”), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

    เท่านี้เราก็จะมี font แบบที่เราอยากได้ไว้ใช้งานในเอกสารครับ หลังจากนั้น เราก็สร้างตัวอักษรเพื่อใช้งาน ตามตัวอย่างนี้ครับ

    // Bold
    BaseFont bf_bold = BaseFont.CreateFont(HttpContext.Current.Server.MapPath(“~/Regist/Theme/fonts/THSarabunNewBold.ttf”), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
    h1 = new Font(bf_bold, 18);
    bold = new Font(bf_bold, 16);
    smallBold = new Font(bf_bold, 14);

    // Normal
    BaseFont bf_normal = BaseFont.CreateFont(HttpContext.Current.Server.MapPath(“~/Regist/Theme/fonts/THSarabunNew.ttf”), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
    normal = new Font(bf_normal, 16);
    smallNormal = new Font(bf_normal, 14);

    เริ่มต้นสร้างเอกสาร PDF

    เมื่อเรากำหนด font ไว้ใช้งานเสร็จแล้ว เราก็สามารถสร้างเอกสารได้เลยครับ  การสร้างเอกสารจะเริ่มจากการกำหนดขนาดเอกสารครับ ตามตัวอย่างนี้

     

    Document pdfDoc = new Document(PageSize.A4, 30, 30, 20, 20);
    PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDoc, Response.OutputStream);
    pdfDoc.Open();

     

    โดยตัวเลข 4 ตัวหลัง layout ของกระดาษคือระยะขอบครับ

    เริ่มใส่องค์ประกอบลงในเอกสาร

    ตัวเอกสารของผมจะเริ่มจากส่วนที่เป็นหัวของเอกสารก่อน ซึ่งจะประกอบด้วยรูปภาพ 1 รูปและข้อความ 1 ข้อความ แต่ปัญหาอยู่การจัดการ layout เพราะเมื่อเราใส่องค์ประกอบเข้าไปมันจะชิดทางด้านซ้ายให้โดยอัตโนมัติ ในกรณีนี้จึงต้องใช้ PdfPTable มาช่วยจัดส่วนหัวเอกสารก่อนครับ ทำการกำหนดขนาดของตารางแล้วจัดองค์ประกอบเข้าไปอยู่ในแต่ละ cell

    private PdfPTable GetHeader() {

    PdfPTable headerTable = new PdfPTable(2);
    headerTable.TotalWidth = 530f;
    headerTable.HorizontalAlignment = 0;
    headerTable.SpacingAfter = 20;
    //headerTable.DefaultCell.Border = Rectangle.NO_BORDER;

    float[] headerTableColWidth = new float[2];
    headerTableColWidth[0] = 220f;
    headerTableColWidth[1] = 310f;

    headerTable.SetWidths(headerTableColWidth);
    headerTable.LockedWidth = true;

    iTextSharp.text.Image png = iTextSharp.text.Image.GetInstance(imagePath + “/thai_gov.png”);
    png.ScaleAbsolute(40, 40);

    PdfPCell headerTableCell_0 = new PdfPCell(png);
    headerTableCell_0.HorizontalAlignment = Element.ALIGN_LEFT;
    headerTableCell_0.Border = Rectangle.NO_BORDER;
    headerTable.AddCell(headerTableCell_0);

    PdfPCell headerTableCell_1 = new PdfPCell(new Phrase(“บันทึกข้อความ”, h1));
    headerTableCell_1.HorizontalAlignment = Element.ALIGN_LEFT;
    headerTableCell_1.VerticalAlignment = Element.ALIGN_BOTTOM;
    headerTableCell_1.Border = Rectangle.NO_BORDER;
    headerTable.AddCell(headerTableCell_1);

    return headerTable;
    }

    เมื่อทำการเพิ่มเข้าไปเอกสารแล้วจะได้ลักษณะตามภาพ

    pdf_header

    หลังจากนั้นผมก็เริ่มใส่องค์ประกอบที่เป็นรายละเอียดของส่วนหัวของเอกสารดังนี้

    private PdfPTable GetHeaderDetail() {
    PdfPTable table = new PdfPTable(2);
    table.TotalWidth = 530f;
    table.HorizontalAlignment = 0;
    table.SpacingAfter = 10;

    float[] tableWidths = new float[2];
    tableWidths[0] = 400f;
    tableWidths[1] = 130f;

    table.SetWidths(tableWidths);
    table.LockedWidth = true;

    Chunk blank = new Chunk(” “, normal);

    Phrase p = new Phrase();

    p.Add(new Chunk(“ส่วนราชการ”, bold));
    p.Add(new Chunk(blank));
    p.Add(new Chunk(“วิเทศสัมพันธ์”, normal));

    PdfPCell cell0 = new PdfPCell(p);
    cell0.Border = Rectangle.NO_BORDER;

    table.AddCell(cell0);

    p = new Phrase();
    p.Add(new Chunk(“โทร”, bold));
    p.Add(new Chunk(blank));
    p.Add(new Chunk(“2012”, normal));

    PdfPCell cell1 = new PdfPCell(p);
    cell1.Border = Rectangle.NO_BORDER;

    table.AddCell(cell1);

    p = new Phrase();
    p.Add(new Chunk(“ที่ มอ”, bold));
    p.Add(new Chunk(blank));
    p.Add(new Chunk(master.ApplicationNo, normal));

    cell0 = new PdfPCell(p);
    cell0.Border = Rectangle.NO_BORDER;

    table.AddCell(cell0);

    p = new Phrase();
    p.Add(new Chunk(“วันที่”, bold));
    p.Add(new Chunk(blank));
    p.Add(new Chunk(master.CreatedDate, normal));

    cell1 = new PdfPCell(p);
    cell1.Border = Rectangle.NO_BORDER;

    table.AddCell(cell1);

    p = new Phrase();
    p.Add(new Chunk(“เรื่อง”, bold));
    p.Add(new Chunk(blank));
    p.Add(new Chunk(“ขออนุมัติเดินทางไปต่างประเทศ”, normal));

    cell0 = new PdfPCell(p);
    cell0.Border = Rectangle.NO_BORDER;
    cell0.Colspan = 2;

    table.AddCell(cell0);

    return table;
    }

    เช่นเคยครับ เราจะต้องใช้ Table มากำหนด layout ของเอกสาร เมื่อทำการเพิ่มแล้วก็จะได้เอกสารหน้าตาดังนี้

    pdf_header_detail

    หลังจากนั้นก็ใส่องค์ประกอบต่าง ๆ เพิ่มเข้าไปทีละชิ้น ๆ ตาม source code ด้านล่าง

     

    private Paragraph GetBodyHeader()
    {
    Phrase p = new Phrase();

    p.Add(new Chunk(“เรียน “, normal));
    p.Add(new Chunk(“รองอธิการบดีฝ่ายองค์กรสัมพันธ์และสารสนเทศ”, normal));

    Paragraph para = new Paragraph(p);
    para.SpacingBefore = 20;
    para.SpacingAfter = 20;

    return para;
    }

    private Paragraph GetBody() {
    Paragraph para = new Paragraph();

    para.FirstLineIndent = 38.1f;

    para.Add(new Phrase(“ด้วย”, normal));
    para.Add(new Phrase(“งานวิเทศสัมพันธ์”, normal));
    para.Add(new Phrase(“ขออนุมัติให้นักศึกษาจำนวน ” + master.StudentCount + ” คน เดินทางไปราชการต่างประเทศระหว่างวันที่ ” + master.StartDate + ” ถึงวันที่ ” + master.EndDate + ” รวม ” + master.PeriodDay + ” วัน เพื่อดำเนินกิจกรรมดังต่อไปนี้”, normal));

    return para;
    }

    private PdfPTable GetActivities()
    {
    PdfPTable table = new PdfPTable(3);

    table.TotalWidth = 530f;
    table.HorizontalAlignment = 0;
    table.SpacingBefore = 20;
    table.SpacingAfter = 20;

    // ชื่อกิจกรรม
    // สถาบัน
    // ประเทศ

    float[] columnWidths = new float[3];
    columnWidths[0] = 200f;
    columnWidths[1] = 200f;
    columnWidths[2] = 130f;

    table.SetWidths(columnWidths);
    table.LockedWidth = true;

    PdfPCell cell0 = new PdfPCell(new Phrase(“กิจกรรม”, bold));
    cell0.HorizontalAlignment = Element.ALIGN_LEFT;
    cell0.Border = Rectangle.NO_BORDER;
    table.AddCell(cell0);

    PdfPCell cell1 = new PdfPCell(new Phrase(“สภานที่”, bold));
    cell1.HorizontalAlignment = Element.ALIGN_LEFT;
    cell1.Border = Rectangle.NO_BORDER;
    table.AddCell(cell1);

    PdfPCell cell2 = new PdfPCell(new Phrase(“ประเทศ”, bold));
    cell2.HorizontalAlignment = Element.ALIGN_LEFT;
    cell2.Border = Rectangle.NO_BORDER;
    table.AddCell(cell2);

    List<MasterActivity> activity = master.GetActivities();

    foreach (MasterActivity a in activity)
    {
    cell0 = new PdfPCell(new Phrase(a.ActivityNameThai, normal));
    cell0.HorizontalAlignment = Element.ALIGN_LEFT;
    cell0.Border = Rectangle.NO_BORDER;
    table.AddCell(cell0);

    cell1 = new PdfPCell(new Phrase(a.HostName, normal));
    cell1.HorizontalAlignment = Element.ALIGN_LEFT;
    cell1.Border = Rectangle.NO_BORDER;
    table.AddCell(cell1);

    Institution host = Institution.GetById(a.HostId);

    cell2 = new PdfPCell(new Phrase(host.CountryName, normal));
    cell2.HorizontalAlignment = Element.ALIGN_LEFT;
    cell2.Border = Rectangle.NO_BORDER;
    table.AddCell(cell2);
    }

    return table;
    }

    private Paragraph GetBodyFooter()
    {
    Paragraph para = new Paragraph(new Phrase(“จึงเรียนมาเพื่อโปรดพิจารณาอนุมัติด้วย จักเป็นพระคุณยิ่ง”, normal));
    para.FirstLineIndent = 38.1f;
    para.SpacingAfter = 25;
    return para;
    }

    private void GetSignature(Document pdfDoc) {

    Paragraph para;
    Phrase p;
    Chunk dotLine = new Chunk(“……………………………………………”, normal);

    //if (master.LevelId.Equals(“D”))
    //{
    // p = new Phrase(dotLine);
    // p.Add(new Chunk(“หัวหน้าภาควิชา”, normal));
    // para = new Paragraph(p);
    // pdfDoc.Add(para);
    //}

    p = new Phrase(dotLine);
    p.Add(new Chunk(“หัวหน้าภาควิชา”, normal));
    para = new Paragraph(p);
    para.SpacingAfter = 15;
    pdfDoc.Add(para);

    p = new Phrase(dotLine);
    p.Add(new Chunk(“คณบดี”, normal));
    para = new Paragraph(p);
    para.SpacingAfter = 15;
    pdfDoc.Add(para);
    }

     

    private PdfPTable GetStudentList() {

    Phrase p;

    PdfPTable table = new PdfPTable(8);
    table.TotalWidth = 530f;
    table.HorizontalAlignment = 0;
    //table.SpacingAfter = 20;
    //headerTable.DefaultCell.Border = Rectangle.NO_BORDER;

    float[] colWidths = new float[8];
    colWidths[0] = 30f;
    colWidths[1] = 70f;
    colWidths[2] = 70f;
    colWidths[3] = 70f;
    colWidths[4] = 70f;
    colWidths[5] = 70f;
    colWidths[6] = 70f;
    colWidths[7] = 70f;

    table.SetWidths(colWidths);
    table.LockedWidth = true;

    PdfPCell cell;

    p = new Phrase(“รายชื่อผู้เดินทางจาก ” + master.StartDate + ” ถึง ” + master.EndDate, normal);

    cell = new PdfPCell(p);
    cell.Colspan = 8;
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    cell.Border = Rectangle.NO_BORDER;
    cell.PaddingBottom = 10;
    table.AddCell(cell);

    #region Header

    cell = new PdfPCell(new Phrase(“ที่”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(“รหัสนักศึกษา”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(“คำนำหน้า”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(“ชื่อ”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(“สกุล”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(“คณะ”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(“วันที่เริ่ม”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(“วันที่สิ้นสุด”, smallBold));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    #endregion

    #region Data

    List<OutboundApplication> apps = master.GetApplications();

    int i = 0;

    foreach (OutboundApplication app in apps)
    {
    cell = new PdfPCell(new Phrase((i + 1).ToString(), smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(app.StudentId, smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(app.TitleName, smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_LEFT;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(app.Firstname, smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_LEFT;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(app.Lastname, smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_LEFT;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(app.FacultyNameThai, smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_LEFT;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(app.StartDate, smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    cell = new PdfPCell(new Phrase(app.EndDate, smallNormal));
    cell.HorizontalAlignment = Element.ALIGN_CENTER;
    table.AddCell(cell);

    i += 1;
    }

    #endregion

    return table;
    }

    และส่วนของ Main program ก็จะเป็นแบบนี้ครับ

    protected void Page_Load(object sender, EventArgs e)
    {
    InitElements();

    try
    {
    // Create PDF document
    Document pdfDoc = new Document(PageSize.A4, 30, 30, 20, 20);
    PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDoc, Response.OutputStream);
    pdfDoc.Open();

    pdfDoc.Add(GetHeader());
    pdfDoc.Add(GetHeaderDetail());

    LineSeparator line = new LineSeparator();

    pdfDoc.Add(line);

    pdfDoc.Add(GetBodyHeader());
    pdfDoc.Add(GetBody());
    pdfDoc.Add(GetActivities());
    pdfDoc.Add(GetBodyFooter());
    GetSignature(pdfDoc);
    pdfDoc.NewPage();
    pdfDoc.Add(GetStudentList());

    pdfWriter.CloseStream = false;
    pdfDoc.Close();
    Response.Buffer = true;
    Response.ContentType = “application/pdf”;
    Response.AddHeader(“content-disposition”, “attachment;filename=Example.pdf”);
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Write(pdfDoc);
    Response.End();
    }
    catch (Exception ex)
    {
    Response.Write(ex.Message);
    }
    }

    สุดท้ายแล้วเราก็จะได้เอกสาร PDF หน้าตาแบบนี้ครับ Example

    บทสรุป

    จะเห็นได้ว่าการสร้างเอกสาร PDF ด้วยเครื่องมือนี้จะกินแรงพอควรนะครับ แต่ข้อดีของ iTextSharp คือน้ำหนักเบาและด้วยการเขียนโค้ดของเรา เราสามารถจะนำอะไรก็ได้ (ตามที่มันมีให้) ไปใส่ในเอกสารได้อย่างอิสระ สำหรับตอนนี้ iTextSharp ยังคงตอบสนองได้ตามความต้องการ แต่เมื่อความต้องการของลูกค้าเปลี่ยนแปลง เราจะได้เห็นกันว่าเครื่องมือตัวนี้จะทรงพลังพอหรือไม่

  • การอัปโหลดไฟล์หลาย ๆ ไฟล์พร้อมกันด้วย Dojo

    ที่มา

    การ upload แฟ้มข้อมูล (File) เป็นกิจกรรมที่อยู่คู่กับ Web application มาเนิ่นนาน ยิ่งเมื่อการพัฒนา Web application เข้าสู่ยุคสมัยของ Web 2.0 และเป็น Web 3.0 ในยุคปัจจุบันก็ยิ่งเกิดเครื่องมือต่าง ๆ เพื่ออำนวยความสะดวกในการ upload ไฟล์มากขึ้นรวมไปถึงความสามารถในการอัปโหลดหลาย ๆ ไฟล์พร้อมกัน (Multi-File Uploading)

    ณ เวลานี้มีเครื่องมือมากมายสำหรับนักพัฒนา Web application  ผู้อ่านอาจมีโอกาสได้ใช้งานเครื่องมือจากบางค่ายบ้างแล้ว แต่ในบทความนี้ผู้เขียนจะแนะนำวิธีการใช้งานเครื่องมือในการทำให้ Web application ของเราสามารถรองรับความต้องการในการอัปโหลดไฟล์หลาย ๆ ไฟล์ได้พร้อมกันตัวหนึ่งชื่อ HTML5 Multi-File Uploader ของ Dojo Toolkit ซึ่งทำงานได้ตามความต้องการของผู้เขียนดังนี้

    ความต้องการ

    1. สามารถ upload file ได้หลาย ๆ ไฟล์พร้อมกัน
    2. upload file ด้วย AJAX
    3. ต้องไม่มีการ Post Back หรือทำให้เกิดการ Load หน้า Web ใหม่
    4. สามารถปรับแต่งได้ตามความต้องการ

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

    ศึกษาคุณสมบัติของเครื่องมือ

    HTML5 Multi-File Uploader เป็นส่วนหนึ่งใน package ชื่อ dojox (dojox/form/Uploader) ซึ่งในความเป็นจริงแล้ว เครื่องมือตัวนี้ไม่ได้เจาะจงเฉพาะการใช้งาน HTML5 เท่านั้นแต่ยังคงใช้งานกับ Flash หรือ iframe ได้ด้วยตามแต่ผู้ใช้จะปรับแต่งเนื่องจาก Web browser แต่ละยี่ห้อก็มีข้อจำกัดแตกต่างกันไปตาม Browser engine และ Rendering engine

    ตามชื่อของเครื่องมือ Uploader ใช้ input ของ HTML5 เป็นองค์ประกอบหลัก จึงต้องกำหนดใน Form ให้รองรับการอัปโหลดไฟล์ด้วยการกำหนด attribute ชื่อ method และ enctype ดังนี้

     

    <form method=”post” enctype=”multipart/form-data”> 

     

    การสร้าง Widget ของ Uploader ทำได้ 2 รูปแบบดังนี้

    Programmatically

    require([

    “dojox/form/Uploader”

    ], function (Uploader) {

    myUploader = new dojox.form.Uploader();

    }

     

    Markup

    <input name=”uploadedFile” multiple=”true” type=”file” data-dojo-type=”dojox/form/Uploader” data-dojo-props=”label: ‘Select Some Files’,……..” />

    <div id=”files” data-dojo-type=”dojox/form/uploader/FileList” data-dojo-props=”uploaderId: ‘uploader’”></div>

    ลองใช้งาน

    เนื่องจากผู้เขียนพัฒนา Web application ด้วย Visual C# จึงจะยกตัวอย่างการประยุกต์การใช้งาน Uploader ร่วมกับ ASP.NET ซึ่งมีขั้นตอนดังนี้

    1. นำ Widget มาวางในส่วนที่เราต้องการ

    <input name=”uploadedfile” type=”file” id=”uploader” data-dojo-id=”fileUploader” data-dojo-type=”dojox/form/Uploader” data-dojo-props=”label: ‘Select files’, url: ‘../Test/TestUpload.ashx’, multiple: true” />
    <input type=”hidden” name=”hdnMasterId” id=”hdnMasterId” value=”test” />
    <input type=”hidden” name=”hdnFileDesc” id=”hdnFileDesc” value=”test” />
    <div id=”files” data-dojo-type=”dojox/form/uploader/FileList” data-dojo-props=”uploaderId: ‘uploader’”></div>

     

    เมื่อสังเกตุแล้วจะเห็นได้ว่าจะไม่มีปุ่ม Submit เนื่องจากผู้เขียนต้องการ upload file แบบ AJAX จึงไม่ต้องการให้ผู้ใช้กด ENTER แล้วส่งฟอร์มทั้งหมดไปทันที อีกจุดหนึ่งคือผู้เขียนต้องการส่งข้อมูลบางอย่างไปในคราวเดียวกันด้วยคือ  hdnMasterId และ hdnFileDesc

     

    ลอง Run ดูน่าจะได้น่าตาประมาณนี้

    ex1

    เมื่อเราลองเลือก file แล้ว ชื่อ file ที่เราเลือกจะแสดงอยู่ตำแหน่งด้านล่าง

    ex2

    2. กำหนดการทำงานในฝั่ง client

    ในขั้นตอนนี้เราจะต้องเขียน JavaScript เพื่อควบคุมการทำงานของ widget โดยผู้เขียนจะกำหนดให้ทำการ upload file แบบ AJAX เมื่อกดปุ่มใดปุ่มหนึ่งดังนี้

    fileUploader..set(“onComplete”, function(){

    //อะไรก็ตามที่ต้องให้ทำเมื่อทำการ upload เสร็จแล้ว

    });

    fileUploader.submit();

     

    3. กำหนดการทำงานในฝั่ง server

    ในส่วนของฝั่ง server เราก็ต้องมีการกำหนดการทำงานเช่นกัน เช่น การจัดเก็บไฟล์ การดึงข้อมูลจากการส่งข้อมูลแบบ AJAX เนื่องจากเรามีการส่งข้อมูลอื่น ๆ ไปด้วย ทั้งนี้เราไม่จะเป็นจะต้องใช้ web form มารองรับในการ upload เราสามารถใช้ ashx มาทำงานแทนที่ได้เลย การเขียนโปรแกรมฝั่ง server เป็นดังตัวอย่างด้านล่าง

    public void ProcessRequest(HttpContext context)
    {
    context.Response.ContentType = “text/plain”;
    JavaScriptSerializer js = new JavaScriptSerializer();
    string result = String.Empty;

    IDictionary<string, string> postData = new Dictionary<string, string>();

    foreach (string name in context.Request.Form.Keys)
    {
    //context.Response.Write(“<br>KEYS: ” + name);
    postData[name] = context.Request.Form[name];
    }

    //result = js.Serialize(new Response(false, postData[“hdnTest”], String.Empty));
    //context.Response.Write(result);

    string masterId = postData[“hdnMasterId”];
    string description = postData[“hdnFileDesc”];

    try
    {
    int len = context.Request.Files.Count;

    for (int i = 0; i < len; i++)
    {
    HttpPostedFile postedFile = context.Request.Files.Get(i) as HttpPostedFile;

    string[] fileNames = postedFile.FileName.Split(‘\\’);
    string fileName = String.Empty;

    if (fileNames.Length > 1)
    {
    fileName = fileNames[fileNames.Length – 1];
    }
    else
    {
    fileName = fileNames[0];
    }

    string[] fileType = postedFile.FileName.Split(‘.’);

    string uploadPath = context.Server.MapPath(Settings.Default.UploadFilePath);
    string newFileName = “[” + masterId + “]_” + fileName;
    string saveFileName = uploadPath + @”\” + newFileName;
    postedFile.SaveAs(saveFileName);

    OutboundMaster app = OutboundMaster.GetById(masterId);
    app.AddAttachedFile(newFileName, description);

    result = js.Serialize(new BizResponse(true));
    }

    context.Response.Write(result);
    }
    catch (Exception ex)
    {
    result = js.Serialize(new BizResponse(false, ex.Message, ex.StackTrace));
    context.Response.Write(result);
    }
    }

    จะเห็นได้ว่าตัวแปรที่มาจากการ post จะอยู่ในรูปแบบของ array ดังนั้นเราจะต้องทำการหาตัวแปรด้วย key ก่อน จากนั้นก็จะเข้าสู่ขั้นตอนการบันทึกไฟล์ตามที่เราออกแบบ

    ทั้งนี้ตัว Uploader มีข้อกำหนดข้อหนึ่งคือจะต้องมีการตอบสนองจากฝั่ง server หากไม่มีจะทำให้ Uploader แสดง error ถึงแม้ว่าการ upload file นั้นเสร็จสิ้นไปแล้วก็ตาม ดังนั้นที่ไฟล์ ashx จึงต้องมีการส่งข้อมูลกลับมาดังตัวอย่างด้านล่างนี้

    context.Response.Write(……);

     

    บทสรุป

    การใช้งาน Uploader อาจจะซับซ้อนมากน้อยขึ้นอยู่กับคนที่นำไปใช้ และถึงแม้ว่าเครื่องมือตัวนี้จะไม่ค่อย compatibility กับ Visual Studio เนื่องจากแนวคิดในการทำงานนั้นแตกต่างกัน แต่ยังคงสามารถนำมาประยุกต์ใช้งานเพื่อให้ได้ผลลัพธ์ตามที่ต้องการได้ และเนื่องจาก Dojo Toolkit นั้นเปิดเผย source code ทำให้เราสามารถทำความเข้าใจและจุดประกายแนวคิดใหม่ ๆ ได้อีกด้วย

  • ข้อแตกต่างระหว่างการลงนามเอกสารด้วย Electronic Signature กับ Digital Signature

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

    และเป็นที่ทราบกันดีว่าวัตถุประสงค์หลักของระบบเอกสารอิเล็กทรอนิกส์คือ การดำเนินการต่างๆ ด้านงานสารบรรณทั้งหมดในรูปแบบไฟล์อิเล็กทรอนิกส์แทนการใช้งานกระดาษ นั่นหมายความว่าเป้าหมายที่สำคัญของระบบนี้คือการดำเนินการทั้งหมดจะต้องดำเนินการผ่านระบบคอมพิวเตอร์ได้ 100% โดยไม่มีการใช้กระดาษเลย แต่ในปัจจุบันระบบยังไม่สามารถทำแบบนั้นได้ โดยเฉพาะในเรื่องของการลงนามเอกสาร เนื่องจากผู้ใช้ยังไม่มั่นใจรูปแบบการลงนามเอกสารในรูปแบบอิเล็กทรอนิกส์เท่าที่ควร จึงเลือกที่จะพิมพ์เอกสารเป็นกระดาษแล้วลงนามกันด้วยปากกาเช่นเดิม อย่างไรก็ตามเทคโนโลยีนี้กำลังจะได้รับการยอมรับมากยิ่งขึ้น เนื่องจากมีกฎหมายออกมารองรับ และสามารถใช้เป็นหลักฐานในชั้นศาลได้แล้ว

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

    จากการศึกษาข้อมูลจากแหล่งต่างๆ พบว่าวิธีการในการลงนามเอกสารแบบอิเล็กทรอนิกส์นั้นมี 2 วิธีหลักๆ คือ  Electronic signature และ Digital Signature ซึ่งมีความหมายและข้อแตกต่างกันดังนี้

    Electronic Signature

    เป็นการทำสัญลักษณ์ หรือลายเซ็นที่อยู่ในรูปแบบอิเล็กทรอนิกส์โดยบุคคล เพื่อเป็นการยืนยันหรือลงนามในเอกสาร สัญลักษณ์ที่นิยมใช้กันได้แก่ รูปภาพลายเซ็นที่เซ็นด้วยหมึกปากกาลงในกระดาษแล้วสแกนเข้าสู่ระบบคอมพิวเตอร์ การใช้เมาส์ หรือนิ้วมือ หรือ stylus วาดรูปลายเซ็นบนหน้าจอคอมพิวเตอร์ ลายเซ็นที่แนบท้ายอีเมล์ การพิมพ์ชื่อด้วยคีย์บอร์ด รูปภาพลายนิ้วมือ การคลิก “I Agree” ใน Electronic form ต่างๆ เป็นต้น

    [ที่มา : https://www.signinghub.com/electronic-signatures]
    [ที่มา : https://www.signinghub.com/electronic-signatures]

    Digital Signature

    Digital Signature เป็น Subset ของ Electronic Signature เนื่องจากเป็นลายเซ็นที่อยู่ในรูปแบบของอิเล็กทรอนิกส์เหมือนกัน แต่ได้เพิ่มเติมคุณสมบัติด้านความปลอดภัยเข้าไป เพื่อให้มีความน่าเชื่อถือมากยิ่งขึ้น คุณสมบัติดังกล่าวประกอบด้วย

    1. Signer Authentication เป็นความสามารถในการพิสูจน์ว่าใครเป็นคนเซ็นเอกสาร ตัวลายเซ็นจะสามารถใช้ในการเชื่อมโยงไปยังบุคคลที่เซ็นเอกสารได้
    2. Data Integrity เป็นความสามารถในการตรวจสอบ หรือพิสูจน์ได้ว่ามีการแก้ไขเอกสารหลังจากที่ได้มีการเซ็นไปแล้วหรือไม่
    3. Non-repudiation การไม่สามารถปฏิเสธความรับผิดชอบได้ เนื่องจากลายเซ็นที่สร้างขึ้นมีเอกลักษณ์ สามารถพิสูจน์ในชั้นศาลได้ว่าใครเป็นผู้เซ็นเอกสาร

    [ที่มา : https://www.signinghub.com/electronic-signatures]
    สรุปข้อดีข้อเสียของ Electronic Signatures และ Digital Signature

    ข้อดี ข้อเสีย
    Electronic Signature – ใช้สัญลักษณ์ หรือรูปภาพลายเซ็นที่ผู้ใช้สามารถเห็นได้ง่าย ทำให้ทราบได้ว่าใครเป็นเจ้าของลายเซ็น (ทราบได้จากการดูรูปลายเซ็น) – ถูกคัดลอกจากเอกสารฉบับหนึ่งไปยังอีกฉบับหนึ่งได้ง่าย

    – ไม่สามารถตรวจจับการแก้ไขเนื้อหา หรือข้อความในเอกสารที่เกิดขึ้นหลังจากการเซ็นได้

    – วิธีการนี้ยังขาดความชัดเจน ไม่สามารถพิสูจน์ได้ว่าเจ้าของลายเซ็นเป็นผู้ลงนามจริงหรือไม่ จึงอาจโดนปฏิเสธความรับผิดชอบในชั้นศาลได้

    Digital Signature – เอกสารที่ผ่านการเซ็นแล้วจะไม่สามารถแก้ไขได้ หากมีการแก้ไขก็จะสามารถตรวจสอบได้ และส่งผลให้ลายเซ็นหมดสภาพไป

    – ผู้เซ็นเอกสารสามารถกำหนดระดับความน่าเชื่อถือได้

    – ผู้เซ็นเอกสารจะไม่สามารถปฏิเสธความรับผิดชอบได้

    – สามารถใช้เป็นหลักฐานในชั้นศาลได้เทียบเท่ากับการเซ็นเอกสารในกระดาษด้วยหมึกปากกา

    – ขึ้นอยู่กับการเข้ารหัสลับ และมีความยุ่งยากในการเชื่อมโยงกับลายเซ็นบนกระดาษ

     

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

     

    แหล่งข้อมูลอ้างอิง : https://www.signinghub.com/electronic-signatures/

  • Resource Governor แนวคิดการจัดการทรัพยากรใน SQL Server 2014

          Resource Governor เป็นแนวคิดใน SQL Server ซึ่งมีมาให้ใช้ตั้งแต่ SQL Server 2008 โดยมีความสามารถในการจัดการ CPU และ Memory ให้พอเหมาะกับการใช้งานของแต่ละฐานข้อมูลได้ แต่ใน SQL Server 2014 ได้มีเพิ่มเติมการจัดการ I/O เพิ่มเข้ามาทำให้ผู้ดูแลสามารถปรับเปลี่ยนการใช้งานได้

          หากจะว่าไปแล้วในการ Tuning ฐานข้อมูลนั้นส่วนใหญ่จะเน้นการทำงานไปที่ CPU และ Memory เป็นส่วนใหญ่ แต่อีกสิ่งหนึ่งที่สามารถปรับแต่งให้ประสิทธิภาพในการทำงานของฐานข้อมูลดีขึ้นได้ ก็คือ I/O นี่เอง ซึ่งทำให้ SQL Server 2014 มีคุณสมบัติในการจัดการทรัพยากรที่หลากหลายและครบถ้วนมากขึ้น

    ในการจัดการ Resource Governor นั้น มีสิ่งสำคัญที่เราควรรู้ 3 สิ่ง ดังนี้

    • Resource Pool หลังจากมีการติดตั้ง SQL Server เสร็จสิ้น ระบบจะสร้าง Resource Pool ตั้งต้นขึ้น 2 ตัว คือ internal และ default ไว้คอยสนับสนุนทรัพยากรที่ผู้ใช้กำหนด ซึ่งผู้ดูแลสามารถสร้าง Resource Pool ขึ้นมาใหม่ได้
    • Workload Group จะมีความสัมพันธ์กับ Resource pool กลุ่มภาระงานแต่ละกลุ่มจะถูกกำหนด Resource Pool ให้ใช้งานได้
    • Classification คือ การจำแนกประเภทการร้องขอที่เข้ามาในระบบให้อยู่ใน Workload Group ที่ได้กำหนดไว้ และเหมาะสมตามการใช้งาน

    โดยสรุปการทำงานตามแผนผัง ดังนี้

    IC122094

          จากแผนผังจะเห็นว่ามีการจำแนกการติดต่อที่ส่งเข้ามาโดยผ่านเงื่อนไขที่ถูกสร้างไว้ภายใน Classification Function ให้เข้าไปยัง Workload Group ที่กำหนดไว้ ซึ่งในแต่ละ Workload Group ก็จะมี Pool ที่จำกัดทรัพยากรไว้เรียบร้อยแล้ว หากเรารู้ว่าการทำงานของกลุ่มไหนมีความต้องการมากกว่าก็สามารถแบ่งทรัพยากรไปให้ใช้งานได้มากกว่า โดยไม่ต้องเสียทรัพยากรไปกับกลุ่มการทำงานที่มีความสำคัญน้อยกว่า ทำให้ประสิทธิภาพในการทำงานเพิ่มมากขึ้น

     

    ตัวอย่างการจัดการทรัพยากรใน Resource Pool

    USE master; 
    GO
    CREATE RESOURCE POOL TestFixIOPool WITH
    (
           MAX_IOPS_PER_VOLUME = 30,
           MIN_IOPS_PER_VOLUME = 1
    	-- MIN_CPU_PERCENT=0,
    	-- MAX_CPU_PERCENT=30,
    	-- MIN_MEMORY_PERCENT=0,
    	-- MAX_MEMORY_PERCENT=30
    );
    GO
    

     

    อ้างอิง : https://technet.microsoft.com/en-us/library/bb934084%28v=sql.105%29.aspx

  • Convert Solution Visual Studio 2005 to 2013

    ในบทความนี้ ผู้เขียนจะขอกล่าวถึงเครื่องมือในการพัฒนาตัวหนึ่งที่ชื่อว่า Visual Studio โดยจะนำเสนอวิธีการ Convert Solution ASP.NET จากเวอร์ชั่นเก่าไปยังเวอร์ชั่นใหม่โดยไม่ต้องสร้างโปรเจคขึ้นมาใหม่ ตัวอย่างในวันนี้จะแสดงการ Convert Project Solution ที่พัฒนาด้วย Visual Studio 2005 ไปพัฒนาบน Visual Studio 2013 ซึ่งแน่นอนครับว่าจะต้องมีการ config ค่าเพิ่มเติมต่างๆ ผู้เขียนจะกล่าวไว้ช่วงท้ายนะครับ เราเริ่มขั้นตอนการ Convert กันเลยดีกว่าครับ

    ขั้นตอนแรก : เตรียมข้อมูลให้พร้อม

    1. เตรียม solution ตัวเก่าของเราให้พร้อม (ในที่นี้เราใช้ solution ของ Visual Studio 2005 ชื่อ GSMISII )

    Capture

    รูปที่ 1 Folder Project Solution Visual Studio 2005

    Capture2

    รูปที่ 2 ไฟล์ Project Solution Visual Studio 2005

         2. เตรียม Visual Studio 2013 ให้พร้อม

    Capture3

    รูปที่ 3 Visual Studio 2013

    ขั้นตอนที่สอง : เริ่ม Convert

          1. เราจะทำการ Convert Solution โดยคลิกขวาไฟล์ Solution ( xxx.sln ) ตามรูปที่ 2 เลือก Open with… ก็จะปรากฎดังรูป

    Capture4

    รูปที่ 4 Keep using Microsoft Visual Studio Version Selector

     

    2. เลือก Keep using Microsoft Visual Studio Version Selector

    Capture5

    รูปที่ 5 Review Project And Solution Changes

         3. Visual Studio จะตรวจสอบว่ามีโปรเจคหรือ Solution ใดบ้าง ตามตัวอย่างมีแค่ 1 Solution กด OK

    Capture10

    รูปที่ 6 Loading solution projects…

          กรณีมีการใช้ Crystal Report จะมีการให้ Backup ก่อนที่จะ Convert (ซึ่งหากต้องการใช้ Crystal Report จะต้องลง SAP Version ที่รองรับกับ Visual Studio 2013 ก่อน)Capture11

    รูปที่ 7 Loading solution projects…

         กรณีที่มีการใช้ Source Control จะมีให้เลือกว่าจะ remove ออกหรือไม่

    Capture9

    รูปที่ 8 Source Control remove

         เสร็จเรียบร้อยแล้ว… จริงหรือ??

    Capture12 

    รูปที่ 9 Solution in Visual Studio 2013

         เรามาลอง Build Solution กันดีกว่า…

    Capture13

    รูปที่ 10 Error Build Solution 

        Oops! Error!!  ไม่ต้องตกใจกันนะครับ เพราะ error พวกนี้ส่วนใหญ่จะเป็นค่า config ที่อยู่ใน file web.config ที่ไม่รองรับกับ control เวอร์ชั่นใหม่อยู่แล้ว ซึ่งรวมไปถึง crystal report ด้วย ตามแก้ให้เรียบร้อย (ใช้ความอดทนเล็กน้อย ให้สังเกตุว่า error assembly ตัวใด สังเกตุเวอร์ชั่นด้วย) แล้วลอง Build ใหม่กันอีกครั้ง

         ปล. สำหรับ Crystal Report สำหรับ Visual Studio 2013 สามารถ Download ได้ที่
    http://scn.sap.com/docs/DOC-7824