การสร้าง JavaScript Dialog ด้วย Bootbox.js

เชื่อว่านักพัฒนาเว็บแอปพลิเคชันทุกคนต้องเคยได้ใช้งาน JavaScript กันเพื่อทำให้เว็บแอปพลิเคชันสามารถทำงานได้ตามความต้องการ  ตัวอย่างตัวที่ใช้กันบ่อยๆ น่าจะเป็น JavaScript Confirm ใช้ในการยืนยันก่อนการดำเนินการต่าง ๆ เช่นการลบข้อมูล เพื่อป้องกันการคลิกปุ่มลบโดยไม่ได้ตั้งใจ ดังรูป   จากรูปจะเห็นว่า JavaScript Confirm บน Google Chrome และ Mozilla Firefox หน้าตาไม่เหมือนกัน ทั้งๆที่ใช้โค้ดเดียวกัน และปัญหาอีกอย่างหนึ่งที่พบคือ หากเราต้องการให้ข้อความ “คุณต้องการลบข้อมูลรายการนี้ใช่หรือไม่?” มีการขึ้นบรรทัดใหม่ ใส่สี เพิ่มขนาดฟอนต์ จัดตัวหนา ตัวเอียงก็ไม่สามารถทำได้เลย แต่ถ้าต้องการให้แก้ปัญหาเหล่านี้ได้ก็ต้องใช้ตัวช่วย นั่นคือ Bootbox.js ซึ่งเป็น JavaScript library ที่ใช้งานร่วมกับ Bootstrap โดยใช้ Bootstrap modal มาทำหน้าที่แทน JavaScript Dialog ต่างๆ ทั้ง Alert, Confirm, Prompt และรวมถึง Custom Dialog ด้วย ทำให้หน้าตาของ Dialog จะเหมือนกันทุก Browser และสามารถจัดรูปแบบการแสดงผลได้ตามต้องการโดยใช้ CSS วิธีการติดตั้ง เข้าไปที่เว็บไซต์ http://bootboxjs.com และเลือกดาวน์โหลดไฟล์ชื่อ bootbox.min.js หรือถ้าไม่ต้องการดาวน์โหลดก็สามารถใช้ CDN (https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js) ได้เช่นกัน ใส่โค้ดอ้างอิงไปยัง bootbox.min.js ใน header tag ดังนี้ <script src=”path/to/script/bootbox.min.js”></script> หรือ <script src=“https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js“></script> ตัวอย่างการใช้งาน Confirm Dialog กำหนดชื่อ CSS class ให้กับปุ่มลบ ในที่ตั้งชื่อว่า “confirm” แทรกโค้ด JavaScript ใน HTML ดังนี้ ลองเปิดเว็บด้วย Google Chrome และ Mozilla Firefox ก็จะได้ผลลัพธ์เหมือนกันดังรูป นอกจาก Confirm Dialog แล้ว ท่านสามารถดูตัวอย่าง Dialog แบบอื่นๆ ได้จากที่นี่ เพียงเท่านี้ก็จะสามารถสร้าง Dialog สวยๆ และมีความยืดหยุ่นไว้ใช้งานได้แล้ว  

Read More »

Unlimited multi level menu in mvc

สวัสดีค่ะวันนี้เรามาว่ากันเรื่องเมนูกันดีกว่านะคะ คำว่าเมนู ผู้เขียนคิดว่าทุกคนต้องรู้จักแน่นอน เพราะในการพัฒนาแต่ละระบบนั้นส่วนใหญ่จะมีส่วนของงานหลายๆส่วน ทำให้มีการออกแบบหน้าจอการใช้งานหลายหน้าจอเพื่อรองรับการทำงานของระบบนั้น เมื่อส่งมอบระบบ แน่นอน!! ค่ะ ความต้องการของลูกค้าไม่หยุดแค่นั้นแน่นอน เมื่อความต้องการเพิ่ม การทำงานของหน้าจอก็เพิ่ม เมนูก็ต้องเพิ่มตามมาเช่นกัน ทำให้ผู้พัฒนาต้องไปแก้โค้ดในส่วนของเมนูทุกครั้งที่มีการเพิ่มเมนู การจัดหมวดหมูของเมนู หรือต้องการปรับเปลี่ยน path ที่ไปเรียกหน้าจอนั้นๆ แค่คิดก็ดูยุ่งยากต่อการจัดการแล้ว วันนี้ผู้เขียนจึงนำวิธีการออกแบบและพัฒนาในส่วนของเมนูที่ผู้เขียนได้ใช้พัฒนาใน MVC มาเป็นตัวอย่างให้ดูกันนะคะ สำหรับผู้อ่านที่ไม่ได้ใช้ MVC ก็สามารถนำไปปรับเปลี่ยนได้ค่ะ หลังจากพัฒนาแล้วระบบก็จะสามารถ เพิ่มเมนู หรือเปลี่ยน path ของเมนู หรือ จัดการกลุ่มของเมนู ได้โดยไม่ต้อง publish ระบบ ทุกครั้งที่มีการแก้ไข ทำให้ง่ายและไม่เสียเวลาในการจัดการเลยค่ะ เรามาเริ่มกันเลยค่ะ ผู้เขียนขอแบ่งการพัฒนาเป็นสองส่วนนะคะ คือ 1.การพัฒนาในฐานข้อมูล : ในส่วนของการออกแบบฐานข้อมูลผู้อ่านต้องออกแบบให้มีการเก็บ id ของ parent เพื่อระบุให้รู้ว่าเมนูตัวนี้เป็นลูกของเมนูตัวไหน ตัวอย่างการออกแบบฐานข้อมูลของเมนู คอลัมภ์ คำอธิบาย  ParentID Id ของ parent MenuID Id ของเมนู MenuName ชื่อของเมนู 2.การพัฒนาระบบ : เป็นการพัฒนาระบบผู้เขียนจะใช้วิธีการพัฒนาแบบใช้ Recursive เข้ามาจัดการในส่วนของการแสดงเมนู โดยข้อดีของ Recursive คือเราสามารถจัดการได้ทั้งส่วนที่มีเมนูย่อย และไม่มีเมนูย่อย ตัวอย่างในส่วนของ Recursive ที่ใช้ใน View เพื่อการแสดงเมนู ( MVC) @helper GetSubMenus(IEnumerable<menutable> siteMenu, Nullable<int> parentID) {     foreach (var i in Model.Where(a => a.ParentID.Equals(parentID)))     {         var submenu = Model.Where(a => a.ParentID.Equals(i.MenuID)).Count();           <li class=”@(submenu > 0 ? “dropdown-submenu” : “dropdown”)”>             <a href=”@(!string.IsNullOrEmpty(i.MenuLink) ? Url.Content(i.MenuLink) : “~/default)” style=”font-size:16px;”>@i.MenuName</a>             @if (submenu > 0)             {                 <ul class=”dropdown-menu”>                     @GetSubMenus(siteMenu, i.MenuID)                     @* Recursive  Call for Populate Sub items here*@                 </ul>             }         </li>     } }   @{     var mymenu = @Model;     var menuParentID = mymenu.First().ParentID; }  @if (mymenu != null && mymenu.Count() > 0) {     <nav class=”navbar navbar-default”>         <div class=”container-fluid”>             <div class=”collapse navbar-collapse” id=”bs-example-navbar-collapse-1″>                 <ul class=” nav navbar-nav”>                     @GetSubMenus(mymenu, menuParentID)                 </ul>             </div>         </div>     </nav> } ตัวอย่างหน้าจอของเมนูที่เรียกใช้ Recursive เพื่อจัดการเมนู

Read More »

รู้จักฟังก์ชัน Excel ตอนที่ 1 เรื่อง ตระกูลท่าน Count

หลาย ๆ ท่านคงใช้ Excel อยู่ในชีวิตประจำวันไม่มากก็น้อย อาจจะชินตากับ Function Count กันอยู่บ่อย ๆ แต่ Function นี้ ไม่ได้มาเดี่ยว ๆ นะคะ ยังมีญาติ ๆ ในตระกูลอีกเพียบเลย มาดูกันค่ะว่า มีอะไรบ้าง และแต่ละ Function นั้นทำงานกันอย่างไรค่ะ COUNT COUNTA COUNTBLANK COUNTIF COUNTIFS Function ตระกูล Count หลัก ๆ ที่ผู้เขียนใช้งานจะมี 5 Function ข้างต้นนะคะ สำหรับในตอนที่ 1 นี้ ผู้เขียนจะนำเสนอ 3 ฟังก์ชันแรกก่อนก็คือ COUNT, COUNTA และ COUNTBLANK ค่ะ ส่วนอีก 2 Function สามารถติดตามต่อได้ในตอนที่ 2 นะคะ   COUNT  สำหรับฟังก์ชันนี้ จะใช้สำหรับนับจำนวนเฉพาะตัวเลข โดยไม่นับตัวอักษรและช่องว่าง ที่อยู่ในช่วงที่เรากำหนด(range) หรือเลือกทีละค่า(value) ตามที่เราต้องการ รูปแบบ Function แบบ value คือ COUNT(value1, [value2],…) value1 คือ ค่าข้อมูลแรกที่ต้องการนับจำนวน ในที่นี้คือใส่ทีละค่า ค่านี้จำเป็นต้องระบุ value2 คือ ค่าข้อมูลที่สอง ที่ต้องการนับจำนวน ไม่จำเป็นต้องมี สามารถเลือกค่าได้เรื่อย ๆ ตัวอย่าง ภาพที่ 1 การเลือกทีละค่าเพื่อนับจำนวนโดยใช้ Function Count   รูปแบบ Function แบบ range คือ COUNT(value1, [value2],…) value1 คือ ค่าข้อมูลแรกที่ต้องการนับจำนวนในที่นี้คือใส่เป็นช่วง การระบุคือ จุดเริ่มต้น:จุดสิ้นสุด ค่านี้จำเป็นต้องระบุ value2 คือ ค่าข้อมูลที่สอง ที่ต้องการนับจำนวน ไม่จำเป็นต้องระบุ สามารถเลือกค่าได้เรื่อย ๆ ตัวอย่าง ภาพที่ 2 การเลือกค่าเป็นช่วงเพื่อนับจำนวนโดยใช้ Function Count ผลลัพธ์ที่ได้ หมายเหตุ เนื่องจาก จากภาพที่ 1 และ 2 มีการเลือกค่าเท่ากับการเลือกแบบช่วงดังนั้นค่าที่ได้จะเท่ากันค่ะ จากผลลัพธ์ที่ได้ จะเห็นได้ว่า Function Count จะนับเฉพาะตัวเลขเท่านั้น ส่วนตัวอักษรหรือช่องว่าง จะไม่ถูกนับค่ะ ซึ่งจะเห็นได้ว่า ข้อมูลคำนำหน้า เกรดและคะแนน จะนับได้แค่ 0 เนื่องจากมีช่องว่างข้อมูลและข้อมูลใน Column นั้นเป็นตัวอักษรค่ะ COUNTA สำหรับฟังก์ชันนี้ จะใช้สำหรับนับจำนวนข้อมูลทั้งหมดทั้งตัวอักษรและตัวเลข แต่ไม่นับช่องว่าง ที่อยู่ในช่วงที่เรากำหนด(range) หรือเลือกทีละค่า(value) ตามที่เราต้องการดังภาพค่ะ รูปแบบ Function แบบ value คือ COUNTA(value1, [value2],…) value1 คือ ค่าข้อมูลแรกที่ต้องการนับจำนวน จะระบุทีละค่าหรือระบุเป็นช่วงก็ได้ แต่ค่านี้จำเป็นต้องระบุ value2 คือ ค่าข้อมูลที่สอง ที่ต้องการนับจำนวน ไม่จำเป็นต้องมี สามารถเลือกค่าได้เรื่อย ๆ ตัวอย่าง จากผลลัพธ์ที่ได้ จะเห็นได้ว่า Function CountA จะนับข้อมูลทั้งหมด ยกเว้นช่องว่าง จะไม่ถูกนับค่ะ ซึ่งจะเห็นได้ว่า ข้อมูลเกรดและคะแนน จะนับได้แค่ 4 เนื่องจากมีช่องว่างข้อมูลละช่อง COUNTBLANK สำหรับฟังก์ชันนี้ จะใช้สำหรับนับจำนวนเฉพาะช่องว่าง ที่อยู่ในช่วงที่เรากำหนด(range) รูปแบบ Function แบบ value คือ COUNTBLANK(range) range คือ ช่วงของข้อมูลที่ต้องการ ตัวอย่าง จากผลลัพธ์ที่ได้ จะเห็นได้ว่า Function CountBlank จะนับเฉพาะข้อมูลที่เป็นช่องว่างค่ะ ซึ่งจะเห็นว่าข้อมูลในที่นี้มีช่องเกรดและช่องคะแนน ที่มีช่องว่าง Column ละช่อง   สำหรับในตอนที่ 1 ก็ขอจบลงเพียงเท่านี้ สามารถติดตาม

Read More »

Migration project.json to csproj format (C#)

ในช่วงการพัฒนาของ .NET Core tooling จนถึงปัจจุบัน มี design/component หลายอย่างที่มีการเปลี่ยนแปลงในลักษณะที่ไม่ compatible กับ version ก่อนหน้า หรือยกเลิกการใช้งาน หนึ่งในนั้นก็คือ project config file ที่เริ่มต้นใช้รูปแบบ json ซึ่งอยู่ใน file ที่ชื่อ project.json แต่ปัจจุบัน เปลี่ยนมาใช้ MSBuild/csproj format การ migration project.json ไปสู่ .csproj format ทำได้ด้วยกันสองวิธีคือ Visual Studio 2017 dotnet migrate command-line tool ทั้งสองวิธีใช้กลไกการทำงานเดียวกัน ซึ่งผลที่ได้จะเหมือนกัน Visual Studio 2017 เปิด project โดยเปิด file .xproj ใน Visual Studio 2017 จะปรากฎ One-way upgrade dialog ขึ้นมาให้เลือก OK, Visual Studio จะทำการ migrate โดย file ที่ถูก migrate (project.json, global.json, .xproj) จะถูกย้ายไปสำรองไว้ใน folder Backup dotnet migrate ใช้ command-line เข้าไปที่ folder ที่เก็บ project และใช้คำสั่ง dotnet migrate ซึ่งจะทำการ migrate โดย file ที่ถูก migrate (project.json, global.json, .xproj) จะถูกย้ายไปสำรองไว้ใน folder Backup <Project Sdk=”Microsoft.NET.Sdk”> … </Project> ข้อแตกต่างระหว่าง project.json กับ csproj format ( อยู่ในรูปแบบ XML-based ซึ่งมี root node ระบุ sdk ที่ใช้คือ Microsoft.NET.Sdk สำหรับ web project sdk ที่ใช้คือ Microsoft.NET.Sdk.Web ) มีดังนี้ Common options ****** JSON format ****** { “name”: “MyProjectName”, “version”: “1.0.0-alpha-*”, “authors”: [ “name1”, “name2” ], “company”: “PSU”, “language”: “en-US”, “title”: “My library”, “description”: “This is my library.”, “copyright”: “PSU 3000”, “userSecretsId”: “xyz123” } ****** csproj format ****** <PropertyGroup> <AssemblyName>MyProjectName</AssemblyName> <PackageId>MyProjectName</PackageId> <VersionPrefix>1.0.0</VersionPrefix> <VersionSuffix>alpha</VersionSuffix> <Authors>name1;name2</Authors> <Company>PSU</Company> <NeutralLanguage>en-US</NeutralLanguage> <AssemblyTitle>My library</AssemblyTitle> <Description>This is my library.</Description> <Copyright>PSU 3000</Copyright> <UserSecretsId>xyz123</UserSecretsId> </PropertyGroup> frameworks ****** JSON format ****** { “frameworks”: { “netcoreapp1.0”: {}, “net451”: {} } } ****** csproj format ****** <PropertyGroup> <TargetFrameworks>netcoreapp1.0;net451</TargetFrameworks>

Read More »

ASP.NET API Security

ปัจจุบันการพัฒนาโปรแกรมในรูปแบบของ API นั้นแพร่หลายมาก เนื่องจากจะทำให้โปรแกรมยืดหยุ่น สามารถพัฒนา Interface ไปในรูปแบบที่หลากหลาย ทั้ง Desktop, Mobile โดยเฉพาะการเรียก API ผ่าน http นั้น ถือว่าค่อนข้างที่จะยืดหยุ่นกับเกือบจะทุก platform ดังนั้น การรักษาความปลอดภัยให้กับ API เหล่านี้ เป็นสิ่งที่จำเป็นและสำคัญอย่างยิ่ง บทความนี้จะพูดถึง 2 เรื่องหลักๆ ได้แก่ การ Authentication และการ Authorization ดังนี้ครับ   Authentication เปรียบเสมือนกับการตรวจสอบว่าใครเป็นผู้ร้องขอ (request) ซึ่งอาจจะเป็นในลักษณะของ username/password หรือเป็น API Key จากใน HTTP Request Header ในบทความนี้จะขอข้ามการพูดถึงการ authentication ด้วย username/password เพราะเชื่อว่าสามารถทำกันได้อยู่แล้ว ไม่ว่าจะเป็นการเขียน provider เองหรือใช้ provider ที่มีมาให้กับ .net framework ซึ่งได้แก่ MembershipProvider โดยจะขอเริ่มพูดในส่วนของ API Key ซึ่งจะใช้คลาส HttpMessageHandler (ทำงานใน http message level ดีกว่าไปทำใน controller แน่นอนครับ) วิธี implement คือ การสร้าง Class ที่ inherite มาจาก DelegatingHandler (ซึ่งมาจาก HttpMessageHandler อีกที) จะให้ override ส่วนของการตรวจสอบ HTTP Request โดยการทำ overriding method ชื่อ SendAsync และเพื่อให้ทำงานได้ จะต้องทำการ register handler ที่ Global.asax ใน Application_Start ด้วยครับ ด้วยคำสั่ง GlobalConfiguration.Configuration.MessageHandlers.Add(new MY_CLASS()); API Key Authentication เราจะต้องมี API Key โดยสามารถเก็บไว้เป็นค่าคงที่ หรือเก็บไว้เป็นข้อมูลในฐานข้อมูล จากนั้นทำการตรวจสอบ Request ที่เข้ามาด้วยคำสั่งต่อไปนี้ HttpRequestMessage.Headers.TryGetValues(“API_KEY”, out myHeader) (ต้องทำการสร้าง instance ของ HttpRequestMessage ก่อนนะครับ — myHeader เป็น type IEnumerable<string>) จากนั้นเรานำค่าในตัวแปรมาตรวจสอบกับ API Key ของเรา ที่เราเก็บไว้ เช่น ถ้าเก็บไว้เป็นค่าคงที่ ก็ตรวจสอบดังนี้ myHeader.FirstOrDefault().Equals(“MySecretAPIKeyNaJa”); หรือถ้าเก็บไว้ในฐานข้อมูล ก็ตรวจสอบดังนี้ db.API_KEY.Where(w => w.KEY == myHeader.FirstOrDefault()).Count() > 0 เป็นต้น หากเป็น API Key ที่ถูกต้อง สามารถ return response ดังนี้ได้ทันที await base.SendAsync(HttpRequestMessage, CancellationToken); ส่วนถ้าเป็น API Key ที่ไม่ถูกต้อง สามารถ return response ดังนี้ เพื่อให้ browser รู้ว่าเกิดอะไรขึ้น HttpRequestMessage.CreateResponse(HttpStatusCode.Forbidden, “Invalid API Key”);   Authorization การทำ authorization นี้จะใช้งาน RoleProvider จาก .NET Framework ซึ่งจะต้องทำการ Implement role provider มาก่อน (รายละเอียด: https://msdn.microsoft.com/en-us/library/8fw7xh74.aspx) หลังจากการทำยืนยันตัวตน (Authentication) แล้ว ควรจะทำการตรวจสอบการอนุญาตให้เข้าถึงทรัพยากรหรือการกระทำ (action) ด้วย ด้วยการใช้งาน AuthorizeAttribute ซึ่งเป็น filter attribute ด้วยวิธีการง่ายๆ

Read More »