BLOG

เรียนเขียนเว็บ ด้วย Blazor (EP1)

เริ่มจากเขียนไม่เป็น...ไปสู่การเขียนเอนจิ้นเว็บเองเลย
มาเรียนรู้ไปพร้อมกัน

🤷‍♂️ทำไมจึงเกิด Series (หรือจะเรียกว่าหนังสือ?) นี้

บทนำ

ตอนแรกเลย โพสนี้ ตั้งใจจะเขียนถึงเรื่อง Blazor สั้นๆ แต่เขียนไป เขียนมา นึกถึงน้องคนนึงที่เคยถามเรื่องให้สอนใช้เอนจิ้นเว็บ LEVEL51 หน่อยแล้วก็ไม่ได้สอนซะที...แล้วก็คนที่ออฟฟิศเล่าให้ฟังว่า ไปให้ทุนนักเรียน ม. ปลายมา น้องบอกว่า "ศึกษาหาความรู้จากบล็็อก LEVEL51" 🤩 ...แล้วก็ นึกถึงว่าเคยเขียนหนังสือสอนเขียนเว็บด้วย ASP.NET...แล้วก็พอดียานแม่ (Microsoft USA) ส่งเหรียญตรา MVP Reconnect มาให้ (ประมาณว่า แกหายไปนานละนะ มาช่วยกันทำมาหากินหน่อย) ก็เลยใจฟูๆ อยากจะจัดเต็ม เขียนให้อ่านกันแบบจุใจอีกซักครั้ง หลังจากหายไปซะนานตั้งแต่สมัยเขียนลง Coresharp.net

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

เรื่องมันเกิดตรงที่...

ก็เรื่องทั้งหมด เริ่มจากการที่ผมว่าแอบดู .NET Core อยู่ห่างๆ ว่าตกลงมันไปจะไปทางไหนกันแน่ และก็แอบลุ้นให้ .NET Framework, .NET Core, .NET Standard มันรวมกันซะที และในที่สุด .NET 5.0 ที่รวมทุกสิ่งได้แล้ว ก็ Release เมื่อประมาณต้นเดือนพฤศจิกายนที่ผ่านมา โดยสิ่งที่ทำให้ผมหันขวับกลับมามองเลยก็คือประสิทธิภาพที่เพิ่มขึ้นอย่างถล่มทลาย ซึ่งมีการ Proven โดยเว็บ Stackoverflow ยอดนิยมของเหล่าโปรแกรมเมอร์อย่างเราๆ ว่า แค่การ Port จาก Framework 4.8 ไปใช้ .NET CORE 3 นั้น ทำให้เวลาในการเรนเดอร์หน้าคำถาม ลดลงจาก 21ms หลือ 15ms หรือ เร็วขึ้นราว 30% และ CPU Usage ของ Server ลดลงไป 80% โอ้วววว

และข่าวที่น่าเศร้าสำหรับผมเองด้วยก็คือ NancyFx ซึ่งเป็น Framework Opensource ในการทำหลังบ้าน ที่ผมโปรดปรานมาก เพราะการสร้าง Route (URL ที่จะเข้ามาใช้งานเว็บ) ใน NancyFx นั้นง่ายดายกว่า ASP.NET MVC อย่างมาก ก็ อยู่โหมด Readonly (Unmaintained) ไปแล้ว เพราะคนทำบอกว่า ASP.NET Core ตัวใหม่ ก็มีความสามารถใกล้เคียงกับ NancyFX อยู่แล้ว และ Contributor (คนที่ช่วยเขียน NancyFx) ก็ย้ายไปเขียน Framework ตัวใหม่แทน ชื่อว่า Carter- โดยตัว Carter นี้ ได้นำพาความง่ายในการสร้าง Route แบบของ NancyFx ไปเกาะอยู่บน ASP.NET Core อีกที เป็นการจากลาอย่างสวยงามของ NancyFx ที่พัฒนากันมากว่า 10 ปี โดยที่แนวคิด "Super Duper Happy Path" ยังคงถูกส่งต่อไปให้รันบน ASP.NET Core ได้อยู่ต่อไป ที่บอกว่ามัน "Super Duper Happy Path" ก็ลองดูโค๊ดนี้เทียบกัน


"SUPER DUPER HAPPY PATH!" 😍


ASP.NET Core MVC 💢

เท่านั้นยังไม่พอ AngularJS (คนละตัวกับ Angular) ที่เป็น Frontend Framework ที่เราเลือกใช้บนเว็บ LEVEL51 และเว็บทั้งหมดที่เราเคยทำให้ลูกค้าของเรา (ซึ่งก็ไม่ได้มีเยอะนักหรอก แหะๆ) ก็จะสิ้นสุดอายุขัยลงภายในปลายปี 2021 นี้อีกต่างหาก โดยสาเหตุหลักเลยที่เราใช้เลือก AngularJS ต่อตั้งแต่ตอนที่ Angular ออก และ React กำลังมา ก็คือเวลาเรารับทำเว็บ เราให้ลูกค้าเลือก Template สำเร็จรูปจากเว็บ Envato แล้วเอามาพัฒนาต่อ การที่จะมานั่งเปลี่ยน Template ที่มัน"สำเร็จรูป" อยู่แล้ว (คือมันทั้ง Responsive มาแล้ว เทสมาแล้ว มี Script ต่างๆ มาหมดแล้ว) ให้เป็น Component ของ React/Angular ก็ดูจะผิดทาง การสวม AngularJS ที่ออกแบบให้เป็น Extension ของโค๊ด HTML ลงไปนั้นเหมาะสมกว่าเห็นๆ

สิ่งสุดท้ายที่ทำให้ผมตัดสินใจว่า ปี 2021 บริษัทเราคงจะต้องเริ่ม Adopt เทคโนโลยี หรือ Framework ใหม่ๆ กับเขาบ้างแล้ว ก็คือ AngularJS อายุมันก็ 10 ปี ตัว NancyFx ก็อายุ 10 ปีแล้ว เหมือนกัน และเราเองก็ต่อสู้ฟาดฟันกับ AngularJS มาพอสมควร (แต่ชอบ NancyFx มาก ไม่มีอะไรจะบ่นเลย) 10 ปีแล้ว เราไม่ได้เรียนรู้อะไรใหม่เลยเหรอเนี่ย!

คงจะได้เวลาต้องขยับตัวได้แล้วละ! จะมาใช้เทคโนโลยีเก่า 10 ปีอยู่ได้ยังไง! 

1) มีสารพัดวิธีการพัฒนา Web Application ในยุคนี้ ทำไมไม่เลือกใช้?

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

💥 1.1) React

ถึงแม้ React จะมี React Native และ Expo ซึ่งแปลว่า เราเรียนรู้ React แล้วครั้งเดียว สามารถความรู้ไปใช้เขียน App บน Android/iOS ได้เลยแบบด่วนมากๆ (ด่วนขนาดเขียนบนเว็บได้เลย) แถมยังมี Bridge.Net ที่ช่วยให้เขียน React ด้วย C# ได้ แต่อย่างไรก็ตาม ผมไม่ค่อยชอบ React ตรงที่

  • React คิดแบบ Single Page App (SPA) First : คือเราจะเห็นว่ามันมีแนวคิดแบบว่า ทุกอย่างเป็น "Component" หรือ ถ้าเรียกภาษาคนที่เคยใช้ Visual Basic หรือ Windows Form ก็คือ "Control" ซึ่งมันดีนะ แต่มันแปลว่า เราจะต้องมานั่งแปลง Template ที่เราสามารถหาซื้อได้จากเว็บ Envato ให้กลายเป็น Component ก่อน และที่สำคัญคือ มันจะไม่สามารถใช้ได้ตรงๆ เพราะว่า Template พวกนั้นก็จะมีการใส่ Script กุบกิบเข้ามาเยอะไปหมด
  • React มีแนวคิดว่า View กับโค๊ดที่เกี่ยวข้อง มันต้องอยู่คู่กันอยู่แล้ว จะไปแยก Model View Controller ทำไม (ลองดู Introducing JSX – React (reactjs.org) ซึ่งเป็นวิธีคิดที่ไม่สอดคล้องกับพวกเรา ที่พัฒนาตัวเองมาจากสาย Windows Application และได้เคยชินกับการทำการแยก View (หน้าจอ) Controller (ตัวโค๊ดที่ควบคุมหน้าจอ) และ Model (ข้อมูล/สิ่งที่เราจะทำงานด้วย)
  • จากความเข้าใจใน Tutorial แรก ของ React ถ้าเราจะสร้างอัลบั้มรูป ขึ้นมา เราจะต้องมี Component ที่เป็นตัวรวมรูปภาพต่างๆ ที่อยู่ในอัลบั้ม และมีอีก Component ที่เป็นตัวรูปที่อยู่ในอัลบั้ม ทำให้โค๊ด View (HTML) ของอัลบั้มนี้ กระจายกันอยู่สองที่ ลองเช็คความเข้าใจแล้วใน Docs ของ React เขาก็บอกให้คิดแบบนีั้นจริงๆ

    ในขณะที่ ถ้าเราต้องการจะทำแบบนี้ใน AngularJS จะเป็นการใส่ ng-repeat วางลงไปที่ส่วนที่จะเป็นรูปภาพภายในอัลบั้ม เพื่อบอกว่า ให้ทำการแสดงผลโค๊ดของรูปภาพนี้ ออกมาซ้ำๆ กัน ตามจำนวนภาพที่อยู่ในอัลบั้มเท่านั้น ทำให้ตอนที่ทำการแก้ไขโค๊ดหน้าเว็บ สามารถมองเห็นโครงสร้างคร่าวๆ ของ Output ได้ทันที แต่สำหรับเว็บ LEVEL51 เราใช้ Razor นะ AngularJS ส่วนมากจะอยู่ใน Backend
  • React ไม่ได้ออกแบบให้ทำ 2 Way Data Bidning ได้แต่ต้น มองอีกอย่างคือ Component ของ React นั้น ทำหน้าที่ในการสร้าง View ของข้อมูล (Model) ที่รับเข้ามา อย่างภาพข้างบน จะเห็นว่า เขาแนะนำให้ 1 Row ของ Product คือ 1 Component เป็นต้น แต่ว่าไม่ได้กำหนดตายตัวถึงการที่จะรับข้อมูลจาก View กลับไปยัง Model ชัดเจน ว่าจะต้องทำอย่างไร โดยคำตอบใน Stackoverflow แนะนำให้ใช้การจับ Event onChange

    นั่นก็คือ React ทำให้เราจะต้องเขียนโค๊ดในการ Update Model เอง เหมือนสมัยก่อนที่เราจะต้องเขียนโค๊ดประมาณว่า currentStudent.Name = txtName.Text สำหรับทุก Text Field ที่รับเข้ามา ในขณะที่ AngularJS สามารถใช้ ng-model="currentStudent.Name" (หรือสามารถเรียกเป็นฟังก์ชั่น Getter/Setter ก็ได้) แบบนี้ได้เลย และตัว Input จะทำการ Update Model เองอัตโนมัติ เมื่อมีการพิมพ์ข้อความลงไป ทำไปได้ถึงขั้น Validation และให้เกิด Animation ด้วย CSS Animation ได้เลยทีเดียว
  • การจะทำให้เว็บรองรับ SEO นั้น ยุ่งเกินไป เนื่องจากทุกอย่างเป็น Component ที่ Render ในฝั่ง Client การจะทำ SEO เลยกลายเป็นว่า ต้องไปทำให้ React สามารถรันบน Server ได้เพื่อที่จะ Pre-Render หน้าเว็บออกมาก่อน แน่นอนว่าเราอาจจะใช้การเขียนแบบเดิมบางส่วน และให้ React บางส่วนก็ได้ แต่แบบนั้น ใช้ Vue ไปเลยจะดีกว่าไหมละ???

สรุปก็คือ ผมรู้สึกว่า React นั้น แนวคิดล้ำหน้า แต่มันไม่ได้แก้ปัญหาจากที่ผมพบเจอจริงๆ ได้ รวมไปถึงมันไปก่อให้เกิดปัญหาอื่น ตามมาอีกต่างหาก

💔1.2) Vue - ไม่ผ่านการคัดเลือก....แค่เพราะมันเป็น JavaScript

สำหรับมนุษย์ที่ใช้ AngularJS มาเกือบ 10 ปี อย่างเรา Vue ดูเหมือนจะเป็นทางเลือกที่ดีที่สุด และมีวิธีการเขียนที่ใกล้เคียงมากๆ กับ AngularJS โดยที่ได้ใจตรงที่ View ของ Vue นั้น แยกกับโค๊ด JavaScript และก็สามารถสร้าง Component ได้อยู่ (ใน AngularJS จะเรียก Directive) บอกได้เลยว่าถ้าใครใช้ AngularJS อยู่ ย้ายมา Vue น่าจะตรงตัวที่สุด ใช้แนวคิดแบบเดิมได้เลยแหละ ซึ่งหลักๆ ที่ LEVEL51 ใช้ก็คือหน้า Admin หลังบ้าน กับหน้า Custom Laptop (ที่พังบ่อยๆ น่ะ) โดยเราใช้วิธีดั้งเดิม ส่งหน้ามาก่อน แล้ว AngularJS ทำตัว UI Config อีกรอบนึง

แต่ด้วยความที่มันเป็น JavaScript มันก็คงยังจะสร้างปัญหาเดิมๆ ให้กับเราได้อยู่ สิ่งที่เป็นปัญหากับเราเยอะที่สุด และเราต่อสู้กับมันเยอะมาก ก็คือมันไม่มี Static Type Checking (ต้องใช้ Tools เพิ่ม) ก็คือเวลาพิมพ์ เราต้องจำได้เองว่าสิ่งนี้มีอะไรให้ใช้บ้าง ทำให้มันมีบั๊กซ่อนอยู่ได้โดยที่เราไม่รู้ตัว และ Debug (ขั้นตอนการหาบั๊ก) ไม่ค่อยจะเจอบ่อยๆ ไหนๆ จะเรียนรู้ใหม่ ก็หาอะไรที่มันไม่เป็นปัญหาเดิมจะดีกว่าไหม!?

🤔1.3) Angular, Flutter - ไม่ผ่านการคัดเลือก เพราะว่าเรากำลังมองหา Framework สำหรับทำเว็บไซต์ ไม่ใช่แค่ Web App / Mobile App

อยากหนี JavaScript ก็มา TypeScript ซี่! Angular จึงน่าจะเป็นตัวเลือกถัดมา แน่นอนว่าถ้าเราจะใช้ Angular เราคงจะใช้มันแต่เกือบ 10 ปีก่อนแล้วละ สิ่งที่ผมไม่ชอบก็คือเรื่องที่คล้ายกับ React คือ ทุกอย่างเป็น Component และมันออกแบบมาเพื่อทำ SPA มากกว่าทำเว็บ ส่วนไหนๆ ถ้าเราจะเรียนรู้กันใหม่ Flutter/Dart ไปเลยก็ดูไม่ได้แย่ แถมยังใช้เป็น App ได้ด้วย แต่ส่วนสำคัญก็คือ Flutter/Dart กลายเป็นเราต้องเรียนภาษาใหม่ (ที่ดูแล้วก็คล้าย React) แทนที่จะใช้ความชำนาญด้าน C# ของเราได้

😯 1.4) Bridge.NET

ตัวเลือกที่น่าสนใจมากอีกตัวหนึ่ง ขอให้รางวัลไอเดียดีที่สุดของทศวรรษนี้เลย ก็คือการเขียน Web Application ด้วย C# และโค๊ด C# จะถูกแปลงเป็น JavaScript อีกที ทำให้เราสามารถใช้ความสามารถของภาษา C# ที่เด่นๆ ได้ทั้งหมด สามารถแชร์โค๊ดที่เป็น Data Type กันได้ด้วย และก็ได้เรื่อง Static Type Checking ตามที่เราใฝ่ฝันไว้

แต่จุดตาย อยู่ที่ใช้ JSX ใน Bridge.NET ไม่ได้ เพราะว่าเวลาจะทำ View จะต้องเขียนเองแบบนี้เลย ไม่สามารถเขียนคล้ายๆ HTML (ภาษาที่ใช้้เขียนเว็บ) ปนลงไปได้ ถ้าหากว่ามันทำได้ อาจจะเสี่ยงลองดูไปแล้วนะ 


(จากบล็อกแนะนำการเขียน React ด้วย Bridge.NET)

แต่ถึงทำได้ ก็จะมีส่วนที่น่ารำคาญแบบเดิมอยู่ดี เรื่องมากจริงๆ 

ก็ถ้าลองคิดดูแล้ว โค๊ดเกือบ 30-40% เลยที่เขียน คือโค๊ดที่ทำให้ Frontend (หน้าเว็บ) กับ Backend (พวกงานหลังบ้านและฐานข้อมูล) คุยกันได้ ด้วยการเรียก REST API เราสามารถแก้ไขเรื่องการแชร์โค๊ดได้ แก้ไขเรื่องการที่ภาษาทำร้ายเราได้ แล้วถ้าเกิดว่ามันมีทางที่จะแก้ไขเรื่องการที่ต้องเขียน Front/Back แยกกันได้ด้วยละ?

💖2) แล้วมาถึง Blazor

พอนั่ง Update ข้อมูลจนถึงตรงนี้ ทำให้ผมนึกขึ้นได้ถึง Blazor ซึ่งตอนแรกเคยอ่านผ่านๆ แล้วราวๆ 1 ปีได้ แต่ไม่สนใจ เพราะรู้สึกว่า มันไปทำงานเหมือนกับ Web Forms สมัย ASP.NET 1.1/2.0 - นั่นก็คือ มันใช้ตัว Browser เป็น Dumb Terminal คือเวลาที่เรากดปุ่ม โค๊ดสำหรับการทำงานของปุ่มนั้น จะถูกประมวลผลบน Server โดยตรง และ Server ส่งหน้าจอส่วนที่เปลี่ยนกลับมาแสดงผลใน Browser

ในสมัย Web forms (ซึ่งผมเชี่ยวมาก ตอนเขียนหนังสือ ASP.NET 2.0 ร่วมกับคุณนเรศ) ตัวหน้าจอที่เรามองเห็น จะเป็นการ Render จากฝั่ง Server ล้วนๆ เลย เช่นการกดปุ่ม และให้แสดงผลข้อความในหน้าเว็บ ก็คือ Server ASP.NET จะเป็นคนรับการกดปุ่ม ทำการประมวลผลโค๊ด แล้วอัพเดทสถานะของหน้าจอในหน่วยความจำของ Server จากนั้นจึงส่งหน้าจอนั้น กลับมาใหม่ทั้งหน้า (เราจะเห็นว่า หน้าจอเว็บ มัน Refresh) ซึ่งความจริงแล้ว สมัยนั้น (คือราว 15 ปีก่อนได้) การเขียน Web Application การที่ทั้งหน้าจอ Refresh แบบนี้ ถือเป็นเรื่องปกติมากนะ

แบบนี้แล้ว Blazor มันจะดีได้ยังไง นี่มันปี 2021 นะ ไม่ใช่ปี 2005!

2.1) ข้อดีของวิธีแบบ Blazor (และวิธีแบบ Web Forms)

  • ไม่ต้องอาศัยความเข้าใจเกี่ยวกับเว็บ เกี่ยวกับ CSS Selector เกี่ยวกับ DOM เกี่ยวกับ jQuery เกี่ยวกับ Ajax เกี่ยวกับ Json อะไรมากมายนัก แค่มีความรู้พื้นฐาน HTML/CSS และ C# สามารถเริ่มเขียน Web Application ที่เป็นลักษณะ Single Page App ได้ทันที
  • ฝั่งหน้าเว็บ (Frontend) กับฝั่งหลังบ้าน (Backend) เป็นโค๊ดชุดเดียวกัน เขียนด้วยภาษาเดียวกัน และก็เรียกได้ว่าไม่มีการแบ่งหน้าบ้าน/หลังบ้าน พอไม่มีอะไรที่เป็นหน้าบ้าน/หลังบ้าน ก็เลยไม่ต้องทำโค๊ดในส่วนที่เป็นการเชื่อมระหว่างหน้าบ้านหลังบ้าน (REST API) เพราะว่าโค๊ดที่เราเขียน สามารถเรียกใช้งานข้อมูลบน Server เช่น เปิดอ่าน/เขียน ข้อมูลลง Database ได้เลยโดยตรง เหมือนกับเขียนโปรแกรมที่ทำงานบน Desktop
  • พอไม่มี API ไม่ต้องมีการส่งข้อมูลข้ามเทคโนโลยี ระหว่าง JavaScript กับภาษาหลังบ้าน จึงไม่มีปัญหาเรื่องการ Serialize ไม่มีการแปลงวันที่ ไม่มีปัญหา Timezone ไม่ตรงกัน ที่ชอบเจอบ่อยๆ 
  • มัน Render หน้าเว็บเต็มๆ มาเลยจาก Server ดังนั้น หมดห่วงเรื่อง Search Engine Optimization (SEO) ไปได้เลย
  • ถ้ามี Line of Business Application (LOB Apps) เก่าๆ ที่เป็น Windows Form และเขียนด้วย .NET อาจจะสามารถ Port มันขึ้นเว็บได้เลย โดยที่ไม่ต้องแก้โค๊ดในส่วนที่ไม่เกี่ยวข้องกับ View เขียนแค่ View ใหม่เป็น HTML ตรงนี้น่าจะเป็นจุดขายที่สำคัญของ Blazor

2.2) ข้อเสียของวิธีการแบบ Blazor

  • ทุกคนที่เปิดดู จะกินทรัพยากรบน Server เพราะว่า Server จะต้องจำ State ของทุกคนเอาไว้ เหมือนทุกคน เปิดโปรแกรม คนละ 1 หน้าต่าง บน Server โดยจากการทดสอบโดย Microsoft พบว่า สำหรับ VM 1 vCPU, แรม 3.5GB นั้น สามารถรองรับ Concurrent ได้ถึง 5,000 User โดยไม่ีส่งผลต่อ Latency จากนั้นก็ขึ้นอยู่กับเราแล้วว่า App เราจะกินหน่วยความจำมากแค่ไหน
  • การ Cluster / Load Balance ทำได้ลำบาก เพราะถ้า Client ไม่ได้ต่อกับ Server เดิม State ก็จะหาย คือ เทคโนโลยีวนกลับมาที่เดิม สมัยก่อนก็จะมีปัญหานี้ ทำให้เราพยายามเขียน Web App เป็น Stateless แล้วให้ State อยู่ที่ Browser (Client) แทน จึงเกิด Ajax, REST API, jQuery, AngularJS, React, Vue มาตามลำดับความต้องการที่ซับซ้อนขึ้นของ Web App ที่รันในหน้า Browser นั่นไง
  • Interaction Time จะช้ากว่า เพราะการประมวลผล เกิดที่ Server ดังนั้น ถ้าไม่ทำความเข้าใจให้ดีๆ และไปเขียนโค๊ดในแบบที่ทุกอย่างต้องส่งกลับไปประมวลผลที่ Server การทำงานก็จะช้ามาก และถ้าไม่เข้าใจจุดนี้ อาจเกิดความยุ่งเหยิงภายหลังในความพยายามที่จะแบ่งโค๊ด Blazor ที่ไม่จำเป็นต้องรันที่ Server ออกมา

สรุปได้ว่า Blazor นั้น มีจุดด้อยที่เรื่องการกินทรัพยากรของ Server, การ เก็บ State และ Response Time ซึ่งเป็นปัญหาดั้งเดิมตั้งแต่สมัยที่เราเขียน Web App แบบเดิมเมื่อ 15-20 ปีที่แล้วนั่นแหละ ดังนั้นถ้าเราจะใช้ Blazor เราก็จะต้องรู้จักการวางแผนที่ดี ถ้าทำตาม Tutorial เป๊ะๆ เราจะได้ข้อเสียของมันมาด้วย

แต่ถ้าอ่านเรื่อง Blazor จะพบว่า มีการพูดถึงการที่ Blazor สามารถทำงานได้บน Browser ได้เลยทั้งหมด โดยไม่ต้องอาศัย Server โดยหน้าเว็บที่เป็น Blazor สามารถใช้ความสามารถ WebAssembly (WASM) ในการเอาโค๊ด C# นั่นแหละ มารันใน Browser เลย แต่ก็ต้องเข้าใจนะว่า มันอยู่ใน Browser จะคาดหวังให้โค๊ดใน Browser ไปต่อฐานข้อมูลตรงๆ ก็จะทำไม่ได้นะ

ส่วนผมนั้น Buy ในตรงที่เป็นข้อดีของมัน คือการที่ไม่ต้องทำ API และการที่โค๊ดฝั่งหน้าเว็บ กับฝั่ง Server สามารถใช้ด้วยกันได้เนี่ยแหละ

🚀3) เริ่มต้นการเขียนเว็บด้วย Blazer

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

ผมจึงเริ่มโครงการเรียนรู้ Blazer โดยมีเป้าหมายที่จะสร้างเว็บ CoreSharp ซึ่งเป็นบล็อกดั้งเดิมของผมขึ้นมาใหม่ด้วย Blazor พร้อมกับบันทึกการเรียนรู้ไปด้วยกันนี่แหละ Series นี้ตั้งใจว่า ต่อให้ไม่เคยเขียนโปรแกรม ไม่เคยเขียนเว็บ ก็สามารถทำตามได้ ดังนั้น มาเรียนไปพร้อมกันเลย!

3.1) เตรียมเครื่องมือกันก่อน

สำหรับเครื่องมือที่ผมแนะนำให้ใช้ จะเป็น Visual Studio Community Edition - หลายคนอาจจะแนะนำให้ใช้ VS Code แต่ว่า กว่าจะทำให้ VS Code มันใช้ทุกอย่างได้คงจะหมดวันซะก่อน ลง Visual Studio เนี่ยแหละ ตอนที่ติดตั้ง ให้เลือกติดตั้งเครื่องมือสำหรับทำเว็บด้วยนะ คือ ASP.NET and web development

3.2) เลือก Template เว็บ

ระหว่างที่ VS ติดตั้ง เราก็มาหา Template ที่ชอบกัน การที่เราจะนั่งทำ Template เพื่อเข้าใจภาษา HTML มากขึ้นก็เป็นเรื่องที่ดี แต่ว่าในชีวิตสมัยนี้ ที่ใครๆ ก็สร้างเว็บได้จากเว็บ Wix.com แบบนี้ การจะมามัวเรียนรู้ภาษา HTML สร้าง Template เอง ทดสอบกับทุกอุปกรณ์ ทำให้มัน Responsive - คือสามารถย่อขยายตามขนาดหน้าจอได้ด้วยเว็บเดียว ไม่ต้องแยก Mobile/Desktop Site คงจะไม่ทัน แนะนำว่า เรียนรู้จากชาวบ้านเขา โดยการหา Web Template ฟรีมาใช้ดีกว่า

สำหรับเว็บที่แนะนำ ลองดูเว็บนี้แล้วกัน 🤩 https://www.free-css.com/free-css-templates พยายามหา Template ที่มีสองหน้า คือหน้า Home กับหน้า Detail อย่างเช่น Template Ramayana นี้ก็ได้

Home Page Detail Page

 

ส่วน Template ที่ผมจะใช้ จะมาจาก Envato Elements นะ เพราะจะทำเป็นเว็บ Coresharp.net ขึ้นมาใหม่จริงๆ ดังนั้น ถ้าอยากทำเป็น จะต้องสามารถประยุกต์สิ่งที่อ่านจากโพส EP นี้ กับเทมเพลทที่เลือกมาได้เอง จึงจะเรียกว่าผ่านบทเรียน

3.3) สร้างโปรเจค

พอติดตั้ง Visual Studio เรียบร้อยแล้ว ทำตามขั้นตอนให้ Login เลือกรูปแบบการใช้งาน ให้เลือกเป็น C# ส่วนเลือกสี แนะนำให้เลือก Dark Mode ไว้ ตาจะได้ไม่ล้ามากเวลาทำงาน (อันนี้ประสบการณ์ตรง จากโปรแกรมเมอร์แก่ ๆ คนนี้ 😅) กดปุ่ม Create a New Project ทางขวา ก็จะเจอกับหน้าจอให้เลือก Template พิมพ์ลงไปว่า Blazor

จากนั้น เลือก Server App - เราสามารถเปลี่ยนเป็น WebAssembly ทีหลังได้ ไม่ต้องกังวล ส่วนตัวเลือก ให้เอา HTTPS/Docker ออกไปก่อน ไว้เราค่อยมายุ่งกับมันอีกรอบหนึ่ง

ในหน้า Configure your new project ตั้งชื่อโปรเจคว่า "CoreSharp.Web" เราจะนิยมตั้งชื่อโปรเจคประมาณนี้ คือ ชื่องาน แล้วห้อยท้ายด้านหลังเป็นชนิดของโปรเจค ส่วน Solution Name ซึ่งมันจะตั้งตาม Project Name ให้เอง ตั้งว่า CoreSharp เฉยๆ แล้วก็หาที่เก็บ Folder ให้จำได้ว่า มันอยู่ที่ไหน

ไม่รู้เหมือนกันว่าทำไมมันกลับมาหน้านี้อีกรอบ ก็ตั้งค่าตามนี้ 

3.4) รู้จักกับ IDE

สำหรับท่านที่ไม่เคยใช้ Visual Studio หรือพวก IDE (Integrated Development Environment - โปรแกรมที่รวมเครื่องมือการเขียนโปรแกรมไว้ที่เดียวกันหมด) ต่างๆ มาก่อน ขอแนะนำสั้นๆ ดังนี้

  1. หน้าจอตรงกลางนี้ จะเป็นส่วนที่เราใช้เขียนโค๊ด
  2. Solution Explorer จะเป็นจุดที่เราเอาไว้ดูว่า ในโปรเจคเรา มีไฟล์อะไรอยู่บ้าง
  3. Toolbar เอาไว้สั่งงาน IDE
  4. Toolbox เครื่องมือที่ใช้ในการวาดหน้าจอ (แต่เราไม่ค่อยได้ใช้หรอกนะ) กับ Test Explorer ซึ่งเราจะได้ใช้ในโอกาสต่อไป

หน้าจอของโปรแกรม IDE นี้ จะสามารถปรับเปลี่ยนได้ โดยการย้ายหน้าต่างไปซ้ายไปขวา แบ่งครึ่งได้ตามความถนัด และถ้าเกิดว่ามีงบประมาณอยู่ แนะนำให้หาซื้อจอภาพมาอีก 1 จอด้วยเลยจะดีมาก การเขียนโค๊ดในหน้าจอหนึ่ง และอ่านข้อมูลได้ด้วยในอีกหน้าจอหนึ่ง ทำให้ชีวิตดีขึ้นมากสุดๆ ส่วนผมนั้น ใช้จอทีวี 4K แล้วแบ่งจอเป็น 4 ส่วนเอาโดยใช้โปรแกรม PowerToys ถ้าเทียบกับซื้อจอ Full HD 24 นิ้ว 4 จอแล้วราคาก็ถูกกว่า ไม่ต้องซื้อขาตั้ง แถมยังใช้ดูหนังได้อีกต่างหาก

พอเปิดได้แล้ว ก็ไม่ต้องรออะไร กด F5 หรือกดปุ่ม Play ตรง Toolbar เพื่อเริ่มการทำงาน (Run) ของโปรแกรม Blazor จาก Template ได้เลย

ส่วนถ้าเกิดว่ากด F5 แล้วมันไม่เกิดอะไรขึ้น ให้เราทำการ Reset Settings ให้เหมือนกันก่อน โดยไปที่เมนู Tools,  Import and Export Settings... จากนั้นเลือก Reset Settings, เลือก No..., แล้วเลือก Visual C# ก่อนกด Finish

🚄4) สำหรับคนที่เขียนโปรแกรมครั้งแรก : เกิดอะไรขึ้น เมื่อเราสั่ง Run

การ Run โปรแกรมนั้น ตัวโปรแกรม Visual Studio จะไปทำงานเบื้องหลังต่างๆ มากมาย กว่าจะมาถึงหน้า Browser ที่เปิดขึ้นมาให้เราเห็น สำหรับท่านที่ไม่เคยเขียนโปรแกรมมาก่อนเลย ควรทราบขั้นตอนเบื้องหลังของมันซักเล็กน้อย เพื่อจะได้เข้าใจภาพรวมได้ดีขึ้น ว่าอะไรเกิดขึ้นตอนไหนบ้าง โดยสรุปแล้ว ตามหนังสือหลายๆ เล่ม เขาจะบอกว่ามันมีขั้นตอนประมาณนี้

  • Compile คือขั้นตอนที่โปรแกรม Compiler นั้น ทำการอ่านโค๊ดต้นฉบับ (Source Code ต่อไปนี้จะเรียกสั้นๆ ว่าโค๊ด) ของเรา แล้วทำความเข้าใจกับมัน ว่าตกลงเราต้องการจะทำอะไร (ถ้าสนใจขั้นตอนย่อยๆ ภายในอีก แนะนำลองอ่านบทความนี้ ถ้าเอาละเอียดสุดๆ ก็บทความนี้) หลังจากขั้นตอนนี้ Compiler จะให้ผลลัพทธ์ออกมาเป็นโค๊ดอีกแบบหนึ่ง ที่เราอ่านไม่ออก แต่ว่าคอมพิวเตอร์เข้าใจ เรียก Object Code (หรือบางทีเรียก Object File) ออกมา
  • Link ส่วนมากจะเป็นอีกโปรแกรมหนึ่ง เรียกว่า Linker ซึ่งจะอยู่ใน Compiler อีกที (ยังไม่เคยเห็นใครทำแยกกัน) Linker จะทำการเชื่อมโค๊ดที่ผ่านการ Compile แล้ว เข้ากับโค๊ดชุดอื่นๆ คือ เวลาเราเขียนโปรแกรมนั้น เราไม่ได้เขียนทุกอย่างขึ้นเอง แต่จะเป็นการเอาของที่คนอื่นเขียนไว้แล้ว เอามาใช้ บางทีก็เรียกกันว่า Library (คือไฟล์ .dll) บางทีก็เรียกกันว่า Framework (คือไฟล์ .dll รวมๆ กัน) บางทีก็เรียกมันว่า Platform (เช่น การเขียน App ใน Android ก็คือเราใช้ Framework/Library/IDE สำหรับ Android) โค๊ดที่เราเขียนจริงๆ มีนิดเดียว แต่จะเป็นส่วนที่ทำให้ App หรือ โปรแกรมของเรา หรือเว็บของเรา ต่างจากของคนอื่น โดยผลลัพทธ์ที่ได้จากการ Link เราจะได้ Executable

    ถ้าบน Windows ไฟล์ที่เป็น Executable จะเป็นไฟล์ .exe หรือ .dll ซึ่งคนอื่น สามารถเอา .exe หรือ .dll ของเรา ไป Link กับเขาต่อก็ได้ การ Link กันนี้ ใน Visual Studio เรียกว่า Add Reference
  • Load หลังจากที่เรามี .exe หรือ .dll แล้ว ถ้าเราต้องการจะให้โปรแกรมสามารถทำงานได้ เราจะต้องอ่านข้อมูลทั้งหมด จาก SSD หรือ HDD (รวมเรียกว่า Disk) ที่เป็น Secondary Storage ในคอมพิวเตอร์ ขึ้นไปยัง RAM ซึ่งคือ Primary Storage ของคอมพิวเตอร์ ที่เป็นแบบนี้เพราะว่า CPU i5 i7 หรือ Ryzen นั้น ไม่รู้จักหรอกว่าอะไรคือ SSD/HDD แลัะมันก็ไม่รู้จัก Drive C, Drive D ด้วย มันรู้จักเฉพาะ RAM เท่านั้น
  • Run นี่คือขั้นตอนที่โปรแกรมเราเริ่มทำงานจริงๆ โดยโปรแกรมที่เราเขียน จะมี Entry Point เสมอ ที่เขาตกลงกันไว้ว่ามันอยู่ตรงไหน โปรแกรมของเราก็จะเริ่มทำงานตั้งแต่ Entry Point นี้ ถ้าในมุมของ CPU มันจะเป็น Instruction แรกของโปรแกรมเรา ที่มันจะอ่านขึ้นมาทำงาน

ถ้าอยากเห็น หลังจากกด Run (ใน Visual Studio) แล้ว สามารถตามไปดูได้ โดยการคลิกขวาตรงชื่อโปรเจคของเราใน Solution Explorer และเลือก Open Folder in File Explorer จากนั้นดูใน Folder obj และ Folder bin จะพบว่ามีไฟล์ชื่อเดียวกับโปรเจคที่เราตั้งชื่อไว้อยู่ แบบนี้ 

และถ้าเราลองดับเบิ้ลคลิก เปิดไฟล์ .exe ให้ทำงานขึ้นมา เราก็จะสามารถเปิด Browser เพื่อกดเล่นเว็บของเราได้ทันทีเลยด้วย! เพราะว่าเว็บที่เขียนด้วย Blazor ซึ่งทำงานอยู่บน ASP.NET Core อีกทีนั้น สามารถ Self-Host หรือมันมี HTTP Server ในตัวเลย (Kestrel) แบบเดียวกับที่ในโปรแกรม SystemX ของเรา สามารถกดดูค่า Sensor ผ่านทางหน้าเว็บ หรือจากมือถือได้นั้นแหละ

(ที่หน้าจอมันไม่สวย เพราะว่าไฟล์ที่หน้าเว็บมันต้องการมันมาไม่ครบ เนื่องจากการเปิด .exe ตรงๆ แบบนี้ คือเรา Run ผิดวิธี แต่ให้ Run แบบนี้เพื่อให้เห็นภาพ)

ส่วนถ้าเป็นการ Run ผ่าน Visual Studio นั้น จะเป็นการรันเว็บของเรา ผ่าน IIS Express อีกทีหนึ่ง โดยเราสามารถเลือกให้ IIS เป็น Reverse Proxy ที่ไปเรียก Kestrel อีกที หรือจะให้เว็บเรา รันอยู่ใน IIS ก็ได้ แบบที่การเขียนเว็บสมัยก่อน จะต้องทำการติดตั้ง Web Application Server เช่น IIS (Express), Apache, Nginx, Lighttpd ก่อน แล้วเรียกเว็บเราโดยผ่าน Server พวกนั้น

👨‍💻5) เริ่มการเรียนรู้ Blazor!

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

ไฟล์ของหน้า Counter จะอยู่ใน Folder Pages ภายใน Solution Explorer สังเกตว่า เวลาที่เราคลิกที่ไฟล์ ตัว Visual Studio จะเปิดไฟล์ขึ้นมาให้เราทันที แต่ว่า Tab ของไฟล์ จะอยู่ชิดขวา และเวลาเราสลับไปไฟล์อื่น หน้าจอจะโดนทับไป ถ้าต้องการบอกว่า เราจะเปิดไฟล์นี้ไว้ ให้ทืำการ Doube Click หรือถ้าเราเริ่มพิมพ์อะไรลงไป ก็จะเป็นการเปิดไฟล์ทิ้งไว้เหมือนกัน

5.1) โครงสร้างของไฟล์ Razor

การเขียนเว็บด้วย Blazor นั้น จะใช้ไฟล์ชนิด Razor (เป็นชื่อเทคโนโลยีีการสร้าง View ของ ASP.NET MVC ที่มาหลังจาก Web Forms อีกทีหนึ่ง) สำหรับไฟล์ Counter.razor จะมี 3 ส่วนที่ต้องสนใจ ดังนี้

  1. คือ Route หรือ URL ที่จะเข้ามาเปิดใช้งานไฟล์นี้ อย่างกรณีของหน้า Counter.razor นี้คือ สามารถเข้ามาได้ด้วย Url /counter ถ้าหากว่าเราเอาเว็บนี้ขึ้น Server ที่ https://www.coresharp.net/ คนทั่วไปก็จะสามารถเข้ามาที่หน้านี้ได้ ด้วย URL https://www.coresharp.net/counter เป็นต้น
  2. คือ View นั่นคือส่วนที่ผู้ที่เข้ามาเยี่ยมชมเว็บของเราจะมองเห็น ส่วนนี้เขียนด้วยภาษา HTML ซึ่งเป็นภาษาดั้งเดิมที่เราใช้ทำหน้าจอเว็บไซต์ตั้งนานมาแล้ว และปัจจุบันก็ยังใช้อยู่ แต่สังเกตว่า ในส่วนนี้ จะมีจุดที่มีเครื่องหมาย @ ปนอยู่
  3. คือ โค๊ด เป็นส่วนที่ควบคุมการทำงานของ View หรือ หน้าเว็บหน้านี้ ส่วนนี้เขียนด้วยภาษา C# จะเห็นว่ามี currentCount และ IncrementCount อยู่ในทั้ง 2 และ 3 เพราะมันเชื่อมโยงกัน

5.2) สำหรับคนที่ไม่เคยเขียนเว็บ : ทำความเข้าใจภาษา HTML ก่อน

ถ้าหากว่าเพิ่งเริ่มเขียนโค๊ดครั้งแรก และยังไม่รู้จักกับภาษา HTML ก็ไม่เป็นไร เดี๋ยวอธิบายแบบลัดสั้นให้ฟัง

สิ่งที่เราจะต้องเข้าใจในภาษา HTML มีแค่นี้:

  • <h1>....</h1> แบบนี้เรียกว่า Tag โดย <h1> เรียกว่า เปิด Tag และ </h1> เรียกว่า ปิด Tag เราใช้ Tag เพื่อกำหนดว่า ข้อความที่อยู่ระหว่าง Tag นั้น จะแสดงผลออกมาอย่างไร เช่น h1 หรือ Header Level 1 จะเป็นตัวอักษรขนาดใหญ่ที่สุด คำว่า Counter เลยตััวใหญ่กว่าเพื่อน
  • Tag มีด้วยกัน 3 ชนิด คือ
    • Block เช่น h1 h2 h3 h4 h5 p div จะเป็น Tag ที่กินพื้นที่ทั้งบรรทัด
    • Inline เช่น button input span img จะเป็น Tag ที่อยู่ในบรรทัด สังเกตว่า:
      • h1 กับ p ในโค๊ดตัวอย่างนั้น ข้อความที่อยู่ใน p จะอยู่คนละบรรทัด กับข้อความใน Tag h1
      • ปุ่มที่เขียน Click me อยู่คนละบรรทัด กับข้อความ Current count ที่อยู่ใน Tag p
      • ข้อความที่เขียนว่า This is not New Line อยู่บรรทัดเดียวกัน กับปุ่ม Click me ถึงแม้ว่า เราจะขึ้นบรรทัดใหม่ใน Source Code ก็ตาม
      • ข้อความที่เขียนว่า This is another Line อยู่คนละบรรทัด กับข้อความ This is not New Line โดยจุดที่เกิดการเริ่มบรรทัดใหม่ คือจุดที่มี Tag <br/>
      • สังเกตว่า ระยะห่างระหว่างบรรทัดที่มีปุ่ม Click me กับ Current Count นั้น ไม่เท่ากับ ระยะห่างระหว่างบรรทัด Click me กับ This is another Line นั่นเป็นเพราะว่า Tag p จะสามารถใส่ระยะ Margin เพื่อดันข้อความให้ห่างกันได้ เพื่อให้รู้ว่าอยู่คนละย่อหน้ากัน (Tag p มีความหมายว่า Paragraph คือ ย่อหน้า)
    • Self-Closing Tag เช่น br img เป็น Tag ที่ไม่มี </...> ที่เขียนเหมือนกันอยู่ข้างหลัง มีแต่เปิด Tag และปิดในตัวมันเลย เป็น Tag ชนิดที่ไม่ได้ระบุการแสดงผลของสิ่งที่อยู่ตรงกลาง แต่ตัวมันเองคือการแสดงผลอะไรบางอย่างออกมา อย่างเช่น br เราจะได้การตัดบรรทัด เพื่อขึ้นบรรทัดใหม่ ส่วน img ใช้สำหรับแสดงรูปภาพ เป็นต้น เราไม่จำเป็นต้องมีอะไรอยู่ระหว่างรูปภาพ และการจะมีตัวอักษรอยู่ระหว่างการตัดบรรทัดมันก็เป็นไปไม่ได้ จริงไหม?
  • สิ่งที่อยู่ระหว่าง Tag เรียกว่า Attribute สังเกตว่า Tag นั้น จะมีการกำหนดไว้ตายตัวแล้วว่า การแสดงผลจะเป็นอย่างไร เช่น h1 เป็นตัวใหญ่ ถ้า p เป็นย่อหน้า แต่บาง Tag จะอนุญาตให้เราสามารถระบุข้อมูลเพิ่มเติมให้กับ Tag ได้ ซึ่งไม่ใช่ข้อความที่เราจะแสดงผล
  • เมื่อแสดงผลในหน้า Browser แล้ว ชิ้นส่วนที่แสดงผลด้วย Tag นั้น เรียกว่า Element

    โดย Attribute สำคัญ ที่มีในทุก Tag คือ:
    • class ใช้สำหรับจัดกลึุ่มของ Element ที่แสดงผล เช่น Element ของ h1 อาจจะมีอยู่หลายที่ แต่เราอยากจะระบุว่า h1 ตัวแรก กับ h1 ตัวนี้ เป็นหัวเรื่องใหญ่สุดเหมือนกัน เราสามารถใส่ว่า <h1 class="topic">....</h1> แบบนี้ก็ได้ ซึ่งเราจะได้เห็นการใช้งานในลำดับต่อไป
    • id ใช้สำหรับระบุชื่อเรียกของ Element ที่แสดงผลตัวนั้น โดยเฉพาะ เช่น Element ของ h1 ในกลุ่ม topic นั้น มี 3 ตัว ถ้าเราต้องการระบุถึง Tag h1 ตัวแรกได้อย่างสะดวก เราสามารถเพิ่ม id ลงไปได้ เช่น <h1 id="firstTopic" class="topic">...</h1> เป็นต้น ซึ่งจะใช้ในการเขียนโปรแกรมเพื่อให้สามารถระบุตัว (Identify) ตัว Element นี้ได้

และจริงๆ แล้ว ในเวอร์ชั่นล่าสุดของภาษา HTML คือเวอร์ชั่น 5 เราสามารถยุบ Tag ทั้งหมด เหลือแค่ div คือ Block และ span คือ Inline ได้เลย และจากนั้นใช้อีกภาษาหนึ่งคือ CSS เพื่อปรับเปลี่ยนการแสดงผลได้ ซึ่งจริงๆ มันสามารถเปลี่ยน div เป็น Inline และ span เป็น Block ก็ยังได้ เดี๋ยวเราจุะมาดูส่วนนี้อีกครั้งหนึ่งภายหลัง

5.3) สำหรับคนที่ไม่เคยเขียนโปรแกรม : ทำความเข้าใจภาษา C# เบื้องต้น

สำหรับภาษา C# นั้น จะมีความซับซ้อนมากกว่าภาษา HTML และต้องอาศัยการเรียนรู้เพิ่มเติมไปเรื่อยๆ เรามาเริ่มกันที่ความรู้ที่เพียงพอสำหรับการทำความเข้าใจโค๊ดในหน้า Counter นี้กันก่อน

  1. Line คือ บรรทัด สังเกตว่าในหน้าจอ จะมีเลขบรรทัดบอกด้วย ในหนึ่งบรรทัดของภาษา C# จะต้องจบด้วย ; เสมอ ซึ่งเป็นปัญหามากๆ สำหรับมือใหม่ที่หัดเขียนโปรแกรม เพราะมักจะลืมใส่ ; เป็นประจำ อันนี้ต้องฝึกให้คล่อง เขียนจบ 1 อย่าง ที่ต้องการทำแล้ว ให้ใส่ ; ทันที ไม่อย่างนั้นแล้ว มันมักจะพาปัญหาอื่นๆ ตามมาทีหลัง
  2. Block คือ กลุ่มของบรรทัด สังเกตว่า Block จะมี { และ } ครอบบรรทัดอยู่ด้วย เวลาที่เราเขียนโค๊ดในบรรทัด ที่อยู่ระหว่าง { และ } นั้น จะเป็นการทำให้เกิด Scope นั่นคือ สิ่งที่อยู่ข้างนอก Scope จะไม่สามารถเข้ามายุ่งสิ่งที่อยู่ข้างใน Scope ของเราได้ มีประโยชน์เพื่อป้องกันการสับสนในการอ่านโค๊ดของโปรแกรม ส่วน Block ในภาพ ตรงบรรทัดที่ 13 จะมีเหมือนโค๊ดอยู่ด้วย ความหมายของมันก็คือ Block นี้ เป็นโค๊ดที่เกี่ยวข้องกับบรรทัดที่ 13 นี้

5.4) สำหรับคนที่ไม่เคยเขียนโปรแกรม : ส่วนประกอบพื้นฐานของภาษา C#

เราเข้าใจแล้วว่า เรามี Line กับ Block เรามาดูส่วนประกอบของบรรทัดที่ 11 เพื่อความเข้าใจที่มากยิ่งขึ้นกันดีกว่า (ในภาพนี้แสดงบรรทัดที่ 13 เพราะว่ามีการพิมพ์โค๊ดเพิ่มเข้าไปนะ)

  1. เรียกว่า Keyword สังเกตว่ามันจะเป็นสีฟ้า เราไม่ต้องมานั่งจำนะ ว่าภาษานี้ เวลาเขียนจะต้องใส่สีฟ้าลงไป มันเป็นแค่ระบบ Syntax Hilighting ของตัว Visual Studio ซึ่งจริงๆ สามารถเปลี่ยนสีก็ยังได้
  2. เรียกว่า Literal คือ ตัวเลข หรือ ตัวอักษร ก็ได้ อย่าง 0 ก็คือ Number Literal ถ้าหากว่าเป็นตัวอักษร เรียกว่า String Literal จะต้องอยู่ในเครื่องหมายคำพูด (ฟันหนู) เสมอ สมัยก่อนก็จะมีปัญหาเรื่องใส่ฟันหนูตัวหน้า แต่ลืมใส่ตัวหลัง ปัจจุบัน Visual Studio จะใส่ตัวหลังให้เองอยู่แล้ว คงจะปัญหาน้อยลง
  3. เรียกว่า Expression หมายถึง สิ่งที่มีค่าออกมา จากในประโยค currentCount = 0 ถ้าอ่านโดยการแปลตรงตัวแบบตอนเราอ่านสมการ ก็จะได้ว่า "ให้ currentCount มีค่าเท่ากับ 0" ซึ่งดูเหมือนเป็นคำสั่ง แต่จริงๆ แล้ว Expression currentCount = 0 นั้น ในภาษา C# จะได้ "คำตอบ" ออกมาด้วย ก็คือได้ ค่า 0 ออกมา

    และจริงๆ Literal 0 นี่ นอกจากมันจะเป็น Literal แล้ว มันก็ยังเป็น Expression เหมือนกัน เพราะว่า 0 ก็จะได้ค่าออกมา เช่นเดียวกับ "CoreSharp" ก็ถือเป็น Expression เพราะว่ามันได้ค่าออกมา 
  4. ทั้ง 1 2 3 รวมกัน เรัียกว่า Statement คือ คำสั่ง เป็นหน่วยย่อยที่สุดของโค๊ดโปรแกรม ที่สามารถทำงานได้
  5. ส่วนสุดท้าย ไม่มีหมายเลขกำกับให้ เพราะว่ามันกระจายอยู่ทุกส่วนเลย ได้แก่ currentCount, myName, IncrementCount พวกนี้ เรียกว่า Identifier หรือ "ชื่อเรียก"

5.5) สำหรับคนที่ไม่เคยเขียนโปรแกรม : โค๊ดเบื้องต้นที่ึควรรู้

เพียงเราเข้าใจ 5 ส่วนนี้ ก็สามารถพอที่จะทำความเข้าใจโค๊ดภาษา C# ได้แล้ว และโค๊ดทั้งหมด ก็จะวนเวียนอยู่แค่ใน 5 สิ่งนี้เท่านั้น นั่นคือ การเอา Identifier มาเขียน Expression ให้ออกมาเป็น Statement

ลองมาดูตัวอย่างอีกหน่อย เพื่อทำความเข้าใจให้มากยิ่งขึ้น

  1. คือ Statement (คำสั่ง) ในการ "ประกาศตัวแปร" คล้ายกับในทางคณิตศาสตร์ ที่เราบอกว่า ให้ X มีค่าเท่ากับ 1 และภายหลัง เราบอกว่า ให้ Y = X - 1 แต่สำหรับกรณีของภาษา C# นั้น ตัวแปร ไม่สามารถใช้ขึ้นมาลอยๆ ได้ จะต้องมีการ ประกาศ ให้ Compiler ทราบก่อนเสมอ ดังนั้น ถ้าเราจะใช้ตัวแปรชื่อ i เราก็จะต้องทำการ ประกาศขึ้นมาก่อน

    ข้อสังเกต:
    • ใน Statement นี้ เทียบกับตัวอย่างที่ Visual Studio ให้มา จะเห็นว่าไม่มีคำว่า private ให้เก็บความสงสัยไว้ก่อน แล้วเดี๋ยวเราจะมาพูดถึงอีกครั้งหนึ่งใน EP ต่อไป ว่าทำไมครั้งนี้ จึงไม่มีคำว่า private
    • int คือ ชนิดของตัวแปร ถ้าหากว่า เราลองใส่ว่า int i = "CoreSharp" ทิ้งไว้แป๊บเดียว จะพบว่า Visual Studio ขึ้นขยุกขยิก (Squiggle) สีแดงๆ ขึ้นมา และถ้าเราเอาเมาส์ชี้ดู จะได้คำแนะนำว่า "Cannot implicitly convert type 'string' to 'int'" (ไม่สามารถแปลงชนิด string เป็น int ได้) นี่คือการ Static Type Checking ที่กล่าวไปในตอนต้น 

  2. สังเกตว่า เราสามารถบอกว่าให้ currentCount = 1 และให้ i = currentCount = 1 ได้ การที่มันเท่ากันสองทอดแบบนี้ ในทางคณิตศาสตร์ เรียกว่า Transitive Property หรือ คุณสมับัติการถ่ายทอด แต่ว่า ในทางด้านการเขียนโปรแกรมของภาษา C# นัั้น ไม่มีสิ่งนี้ ต้องเข้าใจใหม่ว่า ในทางการเขียนโปรแกรม จะเป็นการแทนค่าไปเรื่อยๆ เสมอ นั่นก็คือ
    • i = currentCount = 1 ตัว Compiler จะสร้างคำสั่งให้ CPU ทำการใส่ค่า 1 เข้าไปในตัวแปร currentCount ก่อน และ Expression currentCount = 1 จะได้ค่าออกมาเป็นสิ่งที่ถูกใส่ค่าเข้าไปล่าสุด นั่นก็คือ 1 
    • i = currentCount = 1 1 ในความเข้าใจของ CPU การทำงานในขั้นต่อไปคือ currentCount = 1 ถูกแทนค่าด้วย 1 แล้ว
    • i = 1 และจากนั้นก็คือ นำค่า 1 ใส่ในตัวแปร i
  3. คือ Operator บวก ลบ (*) คูณ และหาร (/) มีความหมายแบบเดียวกับที่เราเข้าใจ ไม่มีอะไรซับซ้อน บางตำราอาจจะโชว์พาว โดยการสอนเรื่อง Operator Precedence คือ ต้องคูณก่อน แล้วค่อยลบ อะไรแบบนี้ และพยายามอธิบายว่า ถ้าเขียนว่า 1 + 3 * 5 / 7 - 2 จะได้ค่าสุดท้ายเป็นเท่าไหร่ บอกเลยว่า ถ้าเขียนแบบนี้มาส่ง ผมให้ไปแก้ใหม่ อยากจะทำอะไรก็ทำให้ชัดเจน ใส่วงเล็บลงไปสิครับ
  4. คือ Unary Operator ซึ่งไม่ค่อยแนะนำให้ใช้ เพราะว่าความหมายกำกวม และสามารถใส่ได้ทั้งด้านหลัง (i++) และด้านหน้า (++i) ซึ่งให้ความหมายต่างกันอีก ยิ่งงงกันเข้าไปใหญ่ เขียนโปรแกรมใหญ่ๆ เราไม่มานั่งโชว์พลังกับเรื่องแค่นี้หรอก 🤣 โปรดจำไว้ว่า การเขียนโค๊ด เน้นที่ การเขียนแล้วอ่านรวดเดียว รู้เรื่อง ไม่ต้องเปิดตำราเช็คอีกทีว่าตกลงตูเข้าใจถูกไหม

    ส่วนความหมายของมันคือ:
    • i++ คือ i = i + 1 แต่ว่า ถ้าเอาไปใส่ใน Statement ว่า int q = 1 + i++; q จะมีค่าเท่ากับ 1 + i
    • i-- คือ i = i - 1 แต่ว่า ถ้าเอาไปใส่ใน Statement ว่า int q = 1 + i--; q จะมีค่าเท่ากับ 1 + i
    • ++i คือ i = i - 1 แต่ว่า ถ้าเอาไปใส่ใน Statement ว่า int q = 1 + ++i; q จะมีค่าเท่ากับ 1 + (i + 1)
    • --i คือ i = i - 1 แต่ว่า ถ้าเอาไปใส่ใน Statement ว่า int q = 1 + --i; q จะมีค่าเท่ากับ 1 + (i - 1)
    บอกเลยว่า นี่ต้องเขียนโค๊ด แล้วรัันเช็คดู ถึงจะเขียนสรุปให้แบบนี้ได้ ถึงบอกไงว่า อย่าใช้มันเลย 😂

5.6) แบบฝึกหัด

เอาละ มาถึงตรงนี้ น่าจะสามารถอ่านโค๊ดตัวอย่างของ Blazor ในหน้า Counter ให้พอเข้าใจได้แล้ว เพื่อเช๋็คว่าเข้าใจจริง ลองเปลี่ยนโค๊ด ให้เวลาคลิ๊กปุ่ม Click Me แล้ว ค่ามันเพิ่มที่ละ 5 แทนที่จะเพิ่มทีละ 1 ดูซิ?

อย่าลืมว่า การแก้ไขโค๊ด เราจะต้องทำการหยุดโปรแกรมของเราก่อน เพราะว่าโค๊ดที่ถูกโหลดขึ้น RAM ไปแล้ว ไม่สามารถถูกแก้ไขได้ (มันมีวิธีทำให้แก้ได้ตอนที่ Run อยู่เลยแหละ แต่ยังไม่ใช่ตอนนี้) โดยการ ปิดหน้าจอ Browser ที่ Visual Studio เปิดขึ้นมาก่อน จากนั้น ทำการแก้ไขโค๊ด แล้วจึงกด Run (F5) อีกครั้ง เพื่อเริ่มขั้นตอนการ Compile, Link, Load, Run อีกรอบหนึ่ง

👨‍💻6) เริิ่มทำ Web Blog ขึ้นมาด้วย Blazor

ก่อนจะไปต่อ มาทบทวนกันก่อนว่า เราเรียนรู้อะไรกันไปแล้วบ้าง

  1. เรารู้แล้วว่า ภาษา HTML มันมี Tag แต่ละ Tag มีหน้าที่เปลี่ยนแปลงการแสดงผล และ Tag มีสองแบบคือ Block กับ Inline
  2. เรารู้แล้วว่า ในภาษา C# เราสามารถสร้างตัวแปรขึ้นมาใหม่ได้ เป็นตัวเลข หรือตัวอักษร และทำความเข้าใจแล้วว่า อะไรคือ currentCount++ รวมไปถึงเข้าใจขนาดที่สามารถเปลี่ยนให้จากการกดแล้วบวกที่ละ 1 กลายเป็น บวกทีละ 5 ได้แล้ว

ก็ด้วยความรู้เท่านี้ เชื่อไหมว่า เราสามารถสร้าง Web Blog (ปลอมๆ) ได้แล้ว!

6.1) หา Layout ของ Template 

ยังมีไฟล์ Template ที่โหลดมาอยู่ใช่ไหม? ถ้าโหลดมาแล้ว ก็เปิด Zip ส่องเข้าใปจนเจอไฟล์ .html ที่อยู่กับ Folder css, images, js แบบนี้ ก็ทำการ Copy ไฟล์กับ Folder css, images, js พวกนี้มาใส่ใน Folder wwwroot ของโปรเจคเรา (สำหรับท่านที่สงสัยว่า ทำไมหน้าจอ Explorer ของผมมี Tab - ผมใช้โปรแกรม Clover ครับ)

จากนั้นให้เรากด Run (F5) ตามปกติ แล้วใส่ URL เป็นชื่อไฟล์ html ลงไป พยายามเลือกหน้าที่มันไม่ค่อยมีอะไรอยู่ตรงกลาง เช่น หน้า 404 หรือหน้า Contact Form เป็นต้น

กรณีถ้าโหลด Template จากเว็บ Free Css Templates อาจจะมีแค่ 2 หน้า ถ้าเลือกใช้เทมเพลทแบบที่มีหน้า Home กับหน้า Detail ตามที่บอก ให้ใช้หน้า Detail นะ

สาเหตุที่เราต้องการเอาหน้าง่ายๆ แบบนี้ออกมา เพราะว่า เราจะต้องทำการหาจุดที่เป็น Content ของทุกหน้า เพื่อให้เราสามารถแยก Layout ของหน้านั้น ออกมาจาก Source Code เพื่อใช้เป็น Layout หรือ โครงของเว็บเรา อีกทีหนึ่งได้ สังเกตว่า เว็บ จะมีส่วนที่เหมือนกันอยู่ทุกหน้า ไม่ข้างบน ก็ข้างล่าง หรือทั้งคู่ พวกที่ซ้ำกันทุกหน้าเนี่ยแหละ คือส่วนที่เราต้องการเอาออกมา

พอเจอหน้าที่เราคิดว่าน่าจะเจาะลงไปได้ง่ายๆ โดยที่เราเองไม่งงแล้ว เราจะใช้เครื่องมือของ Microsoft Edge / Chrome ในการแยกดูว่า ส่วนไหนนะ มันคือส่วนที่เป็น Content ของหน้านั้น (ก็คือส่วนที่เปลี่ยนไป ไม่ใช่สวนที่เหมือนกันทุกหน้า)  โดยการกดปุ่ม F12 บนคีย์บอร์ด ซึ่งจะเปิด Developer Tools ออกมา แล้วก็ใช้การคลิก Source Code ใน Tab Elements ในการชี้ส่องหาไปเรื่อยๆ มันจะ Hilight ให้เราดูว่า โค๊ดที่เราชี้ มันคือบริเวณไหนบนหน้าเว็บ

ถ้าอย่าง Template ที่ผมโหลดมา มันคือ Tag div ที่ id ว่า content 

และเพื่อให้มั่นใจว่า เราเจออันที่ถูก ก็ลองเปิดอีกหน้าหนึ่งเช็็คดูว่าด้วย มันคืออันเดียวกันในอีกหน้าที่เปิดขึ้นมา

จากนั้น กลับมาที่ Visual Studio แล้วก็เปิดไฟล์นั้นขึ้นมาก่อน แล้วจากนั้นกด Ctrl + E จากนั้นปล่อยทั้งสองปุ่มแล้วค่อยกด D (ในเมนูจะเขียนว่า Ctrl+ E, D แปลว่า ให้ทำแบบนี้ โดยใน Status มันจะบอกไว้ด้วยว่า รอปุ่มอยู่ หลังจาก Ctrl + E อยู่นะ) 

คำสั่งนี้ Visual Studio จะจัดโค๊ดให้เป็นระเบียบ 1 รอบ เพื่อให้มือใหม่อย่างเราอ่านง่ายขึ้น จากนั้นกด Ctrl + M, L อีกครัั้ง จะเป็นการยุบโค๊ด HTML ยุ่งๆ ทั้งหมด เป็นสัดส่วนแบบ F12 ของ Browser ทำให้เราสามารถพาตัวเองไปจนเจอช่วงที่เป็น Content ของเราได้ง่ายขึ้น ซึ่งมันก็จะเป็นลำดับเดียวกันกับที่เรากดหาจากในหน้าเว็บเมื่อครู่นี้

พอหาเจอแล้ว ทำการลบด้านในของ Tag ที่ครอบ Content ออก (สำหรับของผมคือ สิ่งที่อยู่ระหว่าง <div id="content"...> </div>) ระหว่างลบ ระวังไม่ให้ลบเกินไปด้วย สังเกตว่า Visual Studio จะทำการย่อหน้า Tag ที่ซ้อนกันให้เราอยู่แล้ว ตอนลบก็แค่ตั้งสติดีๆ ลบเฉพาะ ด้านในของ Tag เป้าหมายของเรา

พอลบแล้ว CTRL+A เพื่อ Copy ข้อความทั้งหมด ไปวางไว้ที่ ส่วนต้นของไฟล์ _Host.cshtml ตรงบรรทัดก่อน <!DOCTYPE html>

จากนั้นก็ Cut เอาส่วนที่อยู่ระหว่าง <body>....</body> ที่อยู่ในไฟล์ _Host.cshtml ของเดิม ที่เขียนว่า <component...>... และจบด้วย </script> เอาไปวางไว้ที่ตรงบริเวณที่เป็น Content ของเรา

อย่างถ้า Layout ที่ผมเลือกมานั้น คือ ระหว่าง Tag <div id="content" ...> </div>

แล้วจากนั้น Cut เอาเฉพาะส่วนที่เขียนว่า <script src="...."></script> ซึ่งจะเป็นบรรทัดสุดท้ายที่เราก็อบมา ย้ายไปวางไว้ก่อน </body>

แล้วจึงลบโค๊ดตั้งแต่ <!DOCTYPE html> จนถึง </html> ของเดิมออก จะเหลือแต่เฉพาะของที่เรา Copy มา

จากนั้น ไปที่ไฟล์ MainLayout.razor แล้วลบทุกอย่่างออก เหลือแต่ @Body

แล้วก็สามารถรันได้เลย (กด F5) จะเห็นว่าหน้าเว็บ Blazor ของเรา เปลี่ยนไปเป็น Template ที่เราเลือกแล้ว เย้ 🥳

เผื่อลืม: ถ้ายังเปิดหน้า Browser ที่ Visual Studio เปิดไว้ให้อยู่ในตอนนี้ ให้ปิดก่อน หรือกด Stop ใน Visual Studio แล้วค่อยกดรัน ไม่อย่างนั้น จะมองไม่เห็นความเปลี่ยนแปลง

แต่ว่า....

  • ไม่มีเมนูทางซ้ายมือ (เนื่องจากเราลบ <NavMenu /> ออกไปจาก MainLayout.razor)
  • มีส่วนที่เป็นคำพูดที่เขียนว่า "An Error...." (หมายเลข 1) โผล่ขึ้นมาด้วย

อย่าไปตกใจ นี่จะเป็นเรื่องต่อไปที่เราจะเรียนรู้กันเลย

✨6.2) มันเป็นเรื่องของ Style

สาเหตุที่ตัวคำว่า An unhandled... นั่นแสดงขึ้นมา ก็เพราะว่า Style ที่ควบคุมการแสดงผลของ Tag นี้ มันถูกลบออกไป ใบ้ให้ว่า มันคือตรงนี้ ที่เคยอยู่ในหน้า _Host.cshtml แต่ที่ไม่ได้ให้ Copy มาด้วย เพราะว่ามันจะมาตบตีกับ Style ที่อยู่ใน Theme ที่เราโหลดมา

ให้ลองเปิดดูไฟล์ css/site.css ดู แล้วดูเฉพาะบรรทัดที่ 33 เป็นต้นไป พร้อมกัน

  1. เรียกว่า CSS Selector โดยเราระบุว่า เราต้องการที่จะกำหนดการแสดงผลของ Element ไหน โดยในหน้าจอของเว็บ Element หมายถึง Tag ที่เราสร้างขึ้นมาใน Source Code นั่นแหละ โดย 1 Tag จะได้ 1 Element
    • #blazor-error-ui นั้นหมายถึงว่า เราต้องการให้ Style นี้ ถูกใช้กับ Element ที่มี Attribute id ว่า "blazor-error-ui" 
    • #blazor-error-io [เว้นวรรค] .dismiss นั้นหมายถึงว่า เราต้องการให้ Style นี้ ถูกใช้กับ Element ที่มี Attribute class ว่า "dismiss" ที่อยู่ด้านในของ Element ที่มี Attribute id ว่า "blazor-error-ui"
  2. เรียกว่า CSS Property ก็คือ การแสดงผลที่เราต้องการ อย่างในตัวอย่างที่วงไว้ให้ตรงบรรทัดที่ 37 ก็คือกำหนดว่า display เป็น none คือ ไม่ให้ Element ที่ถูกเลือกโดย Style นี้ แสดงผลออกมาเลย

​ทีนี้ คงพอจะเดาออกแล้วใช่ไหมว่า สาเหตุที่ตัวข้อความที่บอกว่า Error นั้นแสดงขึ้นมา เป็นเพราะว่า Style ที่ Visual Studio กำหนดมาให้นั้น ไม่ถูกนำมาใช้งานใน Theme ที่เราสร้างขึ้นใหม่ เราก็เลยมองเห็นข้อความว่า เกิด Error ทั้งที่จริงๆ ก็ไม่ได้เกิดอะไรขึ้นหรอก

ถ้าลองมาดูตรงโค๊ดที่เรา Copy มากจากหน้า _Host.cshtml ของเดิมในหัวข้อ 6.1 จะเห็นว่า:

  • มี Element ของ Tag div ที่กำหนด id ไว้ว่า blazor-error-ui ซึ่งจะตรงตาม CSS Selector ในบรรทัดที่ 33 ( #blazor-error-ui) ที่ควรจะถูก CSS Property ในบรรทัดที่ 37 กำหนดให้ปิดการแสดงผล (display : none) แต่เมื่อเราไม่ได้นำ Style ในไฟล์นี้มาใช้งาน ตัว div นี้จึงแสดงผลตามค่ามาตรฐานของมัน (คือ display : block) ทำให้เรามองเห็นข้อความ "An unhandled exception...." ได้
  • มี Element ของ Tag a ที่กำหนด class ไว้ว่า dismiss ที่ซ้อนอยู่ด้านใน Element div ที่กำหนด id ไว้ว่า blazor-error-ui  ซึ่งจะตรงตาม CSS Selector ในบรรทัดที่ 45 

🤔 6.3) รู้ว่าจะพัง ทำไมถึงไม่ให้ Copy โค๊ดที่ว่ามาด้วยละ?

คงจะสงสัยใช่ไหมว่า ทำไมรู้อยู่แล้วว่ามันจะพัง ถึงไม่บอกให้ Copy มาด้วย ตกลงกันก่อนเลยนะ ถ้าหากว่าสงสัย ต่อไปควรทดลองทันที!

การทดลองใส่ Style กลับเข้าไป สามารถทำได้โดยการไปเปิดโค๊ด _Host.cshtml ขึ้นมาอีกครั้ง แล้ววางโค๊ดนี้ลงไป ระหว่าง Tag Head ซึ่งถ้าเราโหลด Theme มา จะพบว่ามี Tag ลักษณะนัี้อยู่แล้วหลาย Tag เลยด้วย

<link href="css/site.css" rel="stylesheet" />

หรือ เราสามารถใช้วิธี ลากไฟล์ css/site.css จากหน้า Solution Explorer แล้วไปวางก็ได้ Visual Studio จะทำการสร้าง Tag นี้ให้เอง สังเกตว่าในตัวอย่าง ผมได้ทำการลบ ~ ออกด้วย เดี๋ยวจะอธิบายต่อในหัวข้อต่อไป

พอเราใส่ลงไป สังเกตว่า จะเกิดความเปลี่ยนแปลงดังนี้กับหน้าเว็บที่ใช้ Theme ที่ผมเลือกมา อันนี้ทดลองจากหน้า /counter

ก่อนใส่ Tag Link หลังใส่ Tag Link ซึ่ง Style ใน css/site.css ถูกนำมาใช้

 

สิ่งที่ต่างกันคือ...

  • ฟอนต์ในหน้าเว็บ จะเป็นคนละฟอนต์กัน โดยฟอนต์หลังจากใส่ Style จะเป็น Font Arial
  • ปุ่ม Click Me โดนเติมสีน้ำเงินลงไป
  • ข้อความ An Unhandled exception หายไปแล้ว

นั่นก็เป็นเพราะว่า Stylesheet (site.css) ถูกนำมาใช้แล้วนั่นเอง ถ้าหากสงสัยว่า Style แต่ละตัว มันมาได้อย่างไร สามารถใช้เครื่องมือ Developer Tools ช่วยหาได้ โดยการใช้เครื่องมือ Elements (Inspect) ตามไปดู แบบนี้

😎6.4) แบบฝึกหัด

ให้ลองทำการแก้ไข css/site.css ให้หน้าเว็บของเรา กลับไปเป็นแบบเดิม และให้ตัวข้อความ An Unhandled... นั้น หายไป ถ้าเป็น แน่นอนว่า ผลของ Style ที่นำมา จะมีผลกับแต่ละท่านแตกต่างกันไป แล้วแต่ Template ที่เลือกมานะ) สำหรับ Template ของผมนั้น จะได้ผลตามภาพนี้

หลังใส่ Tag Link ซึ่ง Style ใน css/site.css ถูกนำมาใช้ หลังการแก้ไข ซึ่ง Style กลับมาเป็นตามเดิม 
(สังเกตว่า Font เปลี่ยน และปุ่ม ไม่มีสีน้ำเงิน)

 

🔥 6.5) สำคัญมาก: ความซับซ้อนของการใส่ Path ที่ถูกต้อง

สำหรับ href เวลาเราลากไฟล์มาวาง จะได้ Path ว่า ~/css/site.css - การที่มี ~/ แบบนี้ มีความหมายว่า ให้ระบบ ASP.NET ทำการแปลง Path ให้ด้วยอัตโนมัติ เพราะว่าในการใช้งานจริง ซึ่งอาจมีการทำ URL Rewriting จะทำเกิดความสับสนได้ อยากให้ตั้งใจอ่านหัวข้อนี้ดีๆ (แต่ถ้าสังเกต จะเห็นว่าในตัวอย่าง ผมได้ลบ ~ ออกนะ)

ลองเล่นๆ ก็ได้ ถ้าหากเราลองแก้ Url ของ Page นั้นให้มี Sub Folder ซ้อนเข้าไป หน้าเว็บเราจะพังทันทีถ้าเข้าจาก Url ที่มี Sub Folder (เช่น /counters/add5) ทั้งที่หน้าเดียวกันนี้ สามารถใช้ได้บน Url ที่ไม่มี Sub Folder (/counter) ย่อยได้ตามปกติ

6.6) สรุปความเข้าใจเรื่อง Path ก่อนไปต่อ

  1. ถ้าเราใส่ Path ใน href โดยไม่มี / นำหน้า เช่น css/site.css จะทำให้ Route ที่มี Sub Folder นั้นทำงานผิดเสมอ จะทำให้ไม่ได้ Style หรือ Script ใดๆ ออกมา เพราะการไม่ใส่ / ด้านหน้า Path ตัว Web Browser จะทำการเรียกไฟล์ โดยอ้างอิงจาก Level เดียวกัน กับ URL ปัจจุบัน
  2. ถ้าเราใส่ Path ใน href โดยมี / นำหน้า เช่น /css/site.css นั้น หมายถึง ให้ Browser เรียกไฟล์ โดยอ้างอิงจากต้นทางที่สุดของ URL ปัจจุบัน ซึ่งจะถูกต้องเสมอ ยกเว้นกรณีเกิดการทำ Url Rewrite ด้วย Reverse Proxy

    เช่น เราเขียนเว็บไว้อยู่ที่ http://internalserver/ แต่ฝ่าย IT ไม่อยากให้ Server ของเราถูกเข้าได้จาก Internet โดยตรง เลยทำการ Rewrite http://www.coresharp.net/blogs/ ให้เรียกไปที่ http://interalserver ต่ออีกรอบ นะั่นก็คือ คนที่เข้า Url http://www.coresharp.net/blogs/homepage จะเหมือนการเรียก http://internalserver/homepage

    ทีนี้เวลาหน้าที่เว็บของ http://internalserver ใส่ Path โดยมี / นำหน้า เช่น /css/site.css ซึ่งตอนที่เราเขี่ยน และทดสอบภายใน เราหมายถึง http://internalserver/css/site.css แต่เนื่องจาก Browser ไม่รู้เรื่องกับเราด้วย ในเมื่อหน้าเว็บ http://www.coresharp.net/blogs ถูกเรียกจาก http://www.coresharp.net มันก็เลยจะกลายเป็นได้ไฟล์ http://www.coresharp.net/css/site.css แทน ซึ่งผิดไฟล์
  3. ถ้าเราใส่ Path ใน href โดยมี ~/ นำหน้า เช่น ~/css/site.css นั้น หมายถึง ให้ระบบของ Blazor ทำการแปลง URL ให้เรา เพื่อให้มันเป็นตำแหน่งที่ถูกให้ โดยอ้างอิงจาก Application Root/Virtual Path ของเว็บเรา ซึ่งจะเกิดขึ้นในกรณีคล้ายของข้อ 2 คือ เราสามารถใส่ Web ของเรา เป็น Sub Folder ของอีกเว็บหนึ่งได้ (แต่ต้องมีการตั้งค่าเพิ่มเติมเล็กน้อย เพื่อให้ใช้งานได้นะ ไม่ขอพูดถึงตอนนี้)

แล้วถ้าอย่างนั้น ควรจะใส่ / หรือ ~/ หรือไม่ใส่เลยดีละ?

สำหรับการไม่ใส่เลย นั่น จะใช้ไม่ได้แน่นอน ดังนั้น จะต้องเลือกใส่

ส่วนสำหรับการใช้งาน 99.99% นั้น สามารถใส่ / นำหน้าได้เลย สำหรับ Path ของ Style (.css) และ Script (.js) ทั้งหมด เพราะว่าการที่เราจะต้องใช้ Url Rewrite หรือ Application Root นั้น โอกาสเกิดขึ้นได้น้อยมากในชีวิตจริง ส่วนมากแล้ว เราก็จะมี Server ใคร Server มัน แต่ละคนมี Url ของตัวเอง หรือไม่ก็ใช้ Sub Domain เช่น https://blogs.coresharp.net การใช้ ~/ จะทำให้เปลืองทรัพยากรของ Server โดยใช่เหตุ เนื่องจากว่ามันจะต้องทำการคิดให้เราทุกครั้งว่า ตกลง จะใส่ Url ว่าอะไร

ดังนั้น ก่อนที่เราจะไปทำอย่างอื่นต่อ ควรทำการเปลี่ยน Path ให้ถูกต้องก่อน สามารถทำได้สองวิธี คือ

  1. ทำการแก้ไขหลายบรรทัดพร้อมกัน ทำได้โดยการกด Alt ค้างไว้ แล้วลาก Cursor ลงมา จะทำให้เราสามารถพิมพ์โค๊ดพร้อมกันหลายบรรทัดได้
  2. ใช้เครื่องมือ Search & Replace ในการแก้ ซึ่งโอกาสน้อยมากที่จะพัง และเร็วด้วย ทำได้โดยการกด  Ctrl + H และใส่ในช่องค้นหา (ด้านบน) และช่อง แทนที่ (ด้านล่าง) ดังนี้
    • ค้นหา [ช่องวาง]href=" และแทนที่ด้วย [ช่องวาง]href="/ จากนั้นกด Replace all
    • ค้นหา [ช่องวาง]src=" และแทนที่ด้วย [ช่องวาง]src="/
    • ค้นหา [ช่องวาง]href="// และแทนที่ด้วย [ช่องวาง]href="/ เพื่อแก้ Path ที่มี // นำหน้า จากการที่เรา Replace ครั้งแรก และไปโดน Path ที่ใส่ / นำหน้าไว้อยู่แล้ว
    • ค้นหา [ช่องวาง]src="// และแทนที่ด้วย [ช่องวาง]src="/

📡7) แสดงผลข้อมูล (ปลอมๆ) ออกมา

มาสรุปกันก่อนว่า เราได้เรียนรู้อะไรไปแล้วบ้าง

  • เราได้เห็นโครงสร้างคร่าวๆ ของ Blazor ว่า มันประกอบไปด้วย _Host.cshtml ที่เป็น Theme ของหน้าเว็บเรา และมันเอาไฟล์ MainLayout.razor, Counter.razor มาผสมกับไฟล์นี้ สร้างเป็นหน้าเว็บให้เราได้
  • เราได้ทำความเข้าใจภาษา HTML เบื้องต้น พอที่จะ Copy Paste โค๊ดชาวบ้านเขาได้แล้ว
  • เรารู้ว่า CSS Selector คืออะไร และ Style คืออะไร มันมีผลกับหน้าเว็บยังไง และเราจะลิงค์ไฟล์ Style เข้ามาที่เว็บเราได้อย่างไร
  • เราเข้าใจว่า ผลของการ Copy มา มันกระทบอะไรกับเว็บของเราบ้าง และได้เรียนรู้การใช้งานเครื่องมือ Developer Tools ในการหาว่า อะไรอยู่ตรงไหน 
  • เราได้เรียนรู้วิธีการเขียนโปรแกรม C# แบบสั้น (มาก) จนเราแก้โค๊ดได้นิดหน่อย

ในขั้นต่อไป ที่หลายท่านอาจจะรอคอยอยู่ ก็คือการให้หน้าเว็บ Blazor ของเรา มันแสดงข้อมูลอะไรซักอย่างออกมาจาฐานข้อมูล แต่เรื่องฐานข้อมูล ขอเก็บไว้ EP หน้า EP ขอเป็นข้อมูลหลอกไปก่อน

7.1) สร้างข้อมูลหลอก

ถ้าจะเอาข้อมูลออกมาแสดง อย่างแรกก็ต้องมีข้อมูล สำหรับภาษาที่เป็น Object Oriented Programming (OOP) อย่าง C# นั้น ข้อมูล และการกระทำที่เกี่ยวข้องกับข้อมูลนั้น จะเก็บอยู่ด้วยกัน ในสิ่งที่เรียกว่า Class ดังนั้นถ้าระบบบล็อกของเราจะเกิดขึ้นได้ ก็จะต้องมี Class สำหรับเก็บบล็อกก่อน มาทำตามไปพร้อมกัน ดังนี้

1) สร้าง Folder ใหม่ในโปรเจค ชื่อว่า Core, ContentSystem, Types ซ้อนกัน โดยการคลิกขวาที่ Project เลือก Add และ New Folder

จากนั้น Add Class โดยการกด Shift+Alt+C (หรือใช้เมนู Add แล้วเลือก New Class) แล้วตั้งชื่อว่า BlogEntry.cs

2) ในไฟล์ BlogEntry.cs คือ Class ของเรา

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

  • Id ชนิดเป็น int
  • Title ชนิดเป็น string
  • Posted ชนิดเป็น DateTime
  • Content ชนิดเป็น string
  • Views ชนิดเป็น int

โดยการทำตามนี้:

  1. พิมพ์ว่า prop  (เรียกว่า Code Snippet)
  2. กด Tab สองครั้ง
  3. พิมพ์ชื่อชนิด เช่น int หรือ string หรือ DateTime
    สังเกตว่า ถ้าเราพิมพ์ว่า date และตาเรามองเห็นแล้วว่า มัน hilight คำว่า DateTime ให้แล้ว สามารถกด Tab ให้มัน Auto Complete ได้เลย ส่วนถ้าเป็น int สามารถกด Tab ข้ามได้เลย ไม่ต้องพิมพ์ 
  4. กด Tab อีกสองครั้ง
  5. พิมพ์ชื่อ Property
  6. กด Enter สองครั้ง เพื่อขึ้นบรรทัดใหม่

จะเห็นว่า เราพิมพ์โค๊ดได้อย่างรวดเร็วมาก ฝึกให้คล่องนะ

นอกจากนี้ เราควรใส่คำอธิบายเพิ่มลงไปใน Property และคลาสของเราได้ด้วย ว่าเราตั้งใจให้มันหมายถึงอะไร โดยการพิมพ์ / สามครั้ง และพิมพ์ลงไปใน Tag <summary>

3) ทำการสร้าง Class อีก 1 คลาส ชื่อว่า BlogDatabase จากนั้น ใส่ Property 2 ตัว ได้แก่

  • Default ชนิดเป็น BlogDatabase (ชนิดเดียวกับชื่อคลาส) สังเกตว่า มีคำว่า static อยู่ด้านหน้าด้วย เราจะมาพูดถึงอีกครั้งในภายหลัง
  • BlogEntries ชนิดเป็น List<BlogEntry> เป็น รายการ ของ คลาส BlogEntry ที่เราสร้างครู่นี้

3) สร้างข้อมูลหลอกขึ้นมา ตามนี้ อนุญาตให้ Copy ได้ จะให้ดี สร้างรอไว้ 4-5 อัน แล้วเปลี่ยนข้อความ หรือวันที่ข้างในให้ต่างกันด้วย และให้ Id = 0, Id = 1, Id = 2 ไล่ไปเรื่อยๆ

public List<BlogEntry> BlogEntries { get; } = new()
{
   new()
   {
      Id = 0,
      Title = "Sample Blog 1",
      Content = "This is a content <b>this is bold</b>",
      Posted = new(2020,12,7,11,11,11),
      Views = 10,                
   },
};

7.2) นำข้อมูลหลอกมาใช้

สิ่งแรกที่เรีาจะต้องทำ ก็คือไป Copy Code สำหรับหน้า Home ของ Template เราออกมา ถ้าเราเปิด Pages/Index.razor ออกมา จะเห็นว่า ตอนนี้มีแค่คำว่า Hello World อยู่ เราไม่ต้องการ Hello World แต่เราต้องการหน้าแรกที่มีรายการโพสของเรา เนื่องจากเรากำลังทำบล็อก

สำหรับ Template ของผม ส่วนที่เป็น Content ของหน้า Home ก็คือ ทุกสิ่งที่อยู่ด้านใน <div id="content"...> ของหน้า index.html ซึ่งผมก็จะไปเปิดหน้า index.html ของ Template ที่โหลดมา แล้ว Copy มาวางลงไปที่ Pages/Index.razor

จากนั้น ใน Template ของผมนั้น จะมีรายการ Post อยู่ เราก็ทำการชี้ดูด้วย Inspector เพื่อจะได้รู้ว่า มันคือส่วนไหน ในโค๊ดที่เรา Copy มาจะได้ไปแก้ถูก อย่าง Template ที่ผมเลือกมานั้น มันคือตรง div ที่ class ชื่อ blog-simple

เราก็กลับมาค้นดูในหน้า Index.razor ที่เรา Copy โค๊ดจาก Template หน้า Home (หรือ index) มาแล้ว แล้วทำการลบตัวอย่างของเขา ให้เหลือแค่ 1 อัน

อย่าลืม : ก่อนแก้ กด Stop หรือ ปิดหน้า Browser ก่อนนะ

จากนั้น เพิ่มบรรทัดว่า

@using Core.ContentSystem.Types

ที่ด้านบนของไฟล์ Index.razor บรรทัดหลัง @page

จากนัั้นในบริเวณที่เราจะแสดงรายการของโพสออกมา เพิ่มโค๊ดว่า

@foreach (var entry in BlogDatabase.Default.BlogEntries)
{
}

จากนั้น ย้ายตัวอย่างของโพส 1 รายการ มาไว้ตรงกลาง ระหว่าง @foreach

จากนั้น ลองรันดูเลย! บึ้มมมมม

😈7.3) สวัสดี Bug ตัวแรก!

พอกดรันปุ๊บ เราจะพบกับหน้าจอแบบนี้ทันที ทำตัวให้ชินไว้ นี่คือสิ่งที่เรียกว่า Bug เราจะต้องเจอกับมันทุกวัน ทั้งวัน ไปอีกนาน ถ้าคิดจะเป็นโปรแกรมเมอร์ 🤣

สำหรับในหน้าจอนี้ Visual Studio บอกว่า โปรแกรมของเราเกิด Exception (ข้อผิดพลาดในโปรแกรม) ซึ่งถ้า Visual Studio ไม่ได้เปิดอยู่ โปรแกรมก็จะดับไปเลย ถ้าเป็นเกม ก็คืออาการ Crash to Desktop ที่เราเจอกันนั่นแหละ

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

ตอนนี้ก็คือ โปรแกรมเกิด Null Reference Exception (Null-Ref-Ex) ซึ่งเป็น Exception หมายเลข 1 ที่เราจะเจอค่อนข้างบ่อยกว่าเพื่อน ถ้าโปรแกรมเขียนมาไม่ค่อยดี เกิดจากการที่เราเรียกใช้ค่าของตัวแปรบางตัว แต่เรายังไม่เคยใส่ค่าให้มันมาก่อน ตอนนี้ Visual Studio มันบอกเราว่า ตอนที่พยายามใช้ BlogDataBase.Default.BlogEntries นั้น ทำให้เกิด NullRefEx เราเลยต้องย้อนกลับไปดูตรงโค๊ดในไฟล์ BlogDatabase.cs อีกที ว่าทำไมมันถึงเกิดขึ้นได้?

7.4) แบบฝึกหัด

ถ้าเขียนโค๊ดตามที่บอกเป๊ะๆ โค๊ดน่าจะเหมือนกับในภาพ ให้ลองพิจารณา (2) ดู แล้วเทียบกับ (1) ว่ามันต่างกันตรงไหน แล้วเราจะแก้ไขให้เว็บเรารันได้ ได้อย่างไร ใบ้ให้ว่า (1) ไม่เคยมีการถูก = อะไรเลย อย่าเพิ่งข้ามไปดูนะ ให้ลองพยายามดูซัก 5 นาที

7.5) ทำการ Binding ข้อมูลออกมาแสดงผล

ถ้าหากว่าแก้ไขได้แล้ว ซึ่งแก้โดยการเติม = new(); ไปด้านหลัง Property Default (ตามโค๊ด) จะเห็นว่า ตรงบริเวณที่เป็นรายการของโพส มีการแสดงผลขึ้นมา เท่ากับจำนวนของตัวอย่างที่เราใส่ลงไปแล้ว เย้~ แต่ว่าข้อมูลที่แสดงนั้น เป็นข้อมูลตัวอย่างตามที่เรา Copy จาก Template มา ไม่ใ่ช่ที่เราพิมพ์ลงไป

public static BlogDatabase Default { get; } = new();

ดังนั้น เราเลยจะต้องทำการ Binding คือ เอาข้อมูลจริง (ที่หลอกๆ) ของเราออกมาใช้ โดยการใส่โค๊ดลงไป ดังนี้

  • วันที่แบบยาว ใช้คำสะั่ง @entry.Posted.Day.ToString()
  • เลขปี ใช้คำสั่ง @entry.Posted.Year
  • ชื่อเดือน ใช้คำสั่ง @entry.Posted.ToString("MMMM")
  • เลขเดือน ใช้คำสั่ง @entry.Posted.Month
  • ชื่อวัน ใช้คำสั่ง @entry.Posted.ToString("ddd")
  • หัวเรื่องของโพส ใช้คำสั่ง @entry.Posted.Title

จากนั้นเมื่อลองรัน จะพบว่า ข้อมูลตัวอย่างของเรา ที่ใส่ลงไป สามารถแสดงขึ้นมาได้แล้ว~! 

7.6 ทำหน้าสำหรับผ่านโพส

Web Blog ที่สมบูรณ์ นอกจากจะมีหน้าแรกที่แสดงรายการแล้ว ก็จะต้องมีหน้าสำหรับเข้าไปอ่านโพสเต็มด้วย เราก็จะต้องสร้างหน้าใหม่ขึ้นมาอีก 1 หน้า เราเลยต้องสร้างขึ้นใหม่ก่อน สามารถทำได้โดยการคลิกขวา แล้วเลือก Add -> Razor Component ตั้งชื่อว่า BlogDetail.razor และให้ทำการแก้โค๊ดเป็นแบบนี้

@page "/blogs/{BlogEntryId:int}"

<h1>Blog Detail of @this.BlogEntryId</h1>

@code {
    [Parameter]
    public int BlogEntryId { get; set; }
}

พอจะเดาได้ไหมว่า เราแก้ไขอะไร? 😊 สิ่งที่เราทำก็คือ

  • บอกว่า ให้หน้านี้ ทำการจับ Path ที่เป็น Pattern ว่า /blogs/(ตัวเลข) เช่น /blogs/1 หรือ /blogs/2 เป็นต้น (ระบุว่าเป็นตัวเลข โดยการใส่ :int)
  • สั่งให้เอาตัวเลขที่จับได้จาก Url มาใส่ลงไปใน Property BlogEntryId สังเกตว่า เราตั้งชื่อ Property ตรงกับ Pattern ที่อยู่ใน @page และมี [Parameter] แปะอยู่ข้างบน

และถ้าเราทดสอบโดยการเปิด Url /blogs/1 (หรือ /blogs/1548832489 ก็ได้) เราก็จะได้หน้าจอที่มี Element H1 ที่แสดงเลขตาม Url ที่เราใส่ลงไปออกมา แบบนี้เรียกว่าการ ส่ง Parameter ไปที่หน้า Razor Component ของเรา ด้วย Url

ตอนนี้ในเมื่อเราสามารถส่ง Parameter มาได้แล้ว ก็เหลือแค่ต้องอ่านค่าออกมาแสดงผล ซึ่งเราสามารถทำได้ โดยการเพิ่มโค๊ดลงไป

@page "/blogs/{BlogEntryId:int}"
@using Core.ContentSystem.Types

<h1>@this.CurrentEntry.Title</h1>
<p>
    @((MarkupString)this.CurrentEntry.Content)
</p>
 
@code {
 
    [Parameter]
    public int BlogEntryId { get; set; }

    public BlogEntry CurrentEntry { get; set; } 

    protected override void OnParametersSet()
    {
        this.CurrentEntry = BlogDatabase.Default.BlogEntries
                                .Where(entry => entry.Id == this.BlogEntryId)
                                .FirstOrDefault();
    }
}

😱 โค๊ดเริ่มยาวแล้วสิ พอจะเดาได้ไหมว่าเราเพิ่มอะไรลงไปบ้าง?

  • เราเพิ่ม Property CurrentEntry เข้ามา ตามชื่อของมันเลย ก็คือ โพส (BlogEntry) ที่คนเข้าเว็บต้องการจะอ่าน
  • ตรงที่เขียนว่า OnParametersSet... ถ้าอ่านเป็นภาษาไทยเลย ก็คือ ให้ พอ Parameter ถูกตั้งค่าแล้ว ให้ CurrentEntry ของตัวนี้ เท่ากับ การเลือกรายการ (Where) จาก BlogDataBase.Default.BlogEntries เอาเฉพาะตัวที่ Id มีค่าเท่ากับ BlogEntryId แล้วตัดเอาแต่ตัวแรกออกมา (First) หรือ เอาตัวมาตรฐาน (Default) ก็ได้
  • เราเปลี่ยนจากให้แสดง Blog Detail of (ตัวเลขที่รับเข้ามา) เป็น CurrentEntry.Title หรือ เอา Title ของ CurrentEntry ออกมา

แล้วถ้าสงสัยว่าจาก Url /blogs/0 มันมาเชื่อมโยงกันได้ยังไง ลองดูภาพนี้ประกอบ อาจจะดูยุ่งหน่อย ค่อยๆ ตั้งใจดูตามเส้นไป

  1. จาก Url ที่ผู้ชม พิมพ์เข้ามา.....
  2. ถูกแทนที่เข้าตาม Pattern ของ Route ที่เรากำหนด
  3. และถูกเก็บเข้าใน Property BlogEntryId
  4. ค่าของ BlogEntryId ถูกเอาไปใช้ใน OnParametersSet() เพื่อใช้ในการเลือก BlogEntry ที่อยู่ในรายการ BlogEntries ออกมา โดยดูที่ค่าของ Id ว่าต้องเท่ากับเลขที่อยู่ใน Property BlogEntryId
  5. ตัว BlogEntry ที่ตรงตามเงื่อนไข ถูกเก็บใส่ Property CurrentEntry
  6. ค่าของ CurrentEntry ถูกเอาไปใช้ในบรรทัดที่ 4 และ 7 แต่ว่าเราไม่ได้ใช้ CurrentEntry เฉยๆ เราใช้ Property Title และ Property Content เพื่อจะเอา Title และ Content ของ BlogEntry ออกมา

สำหรับการทำให้หน้านี้ มีดีไซน์เดียวกับ Template ที่เราได้มา ขอไม่กล่าวถึงนะ เพราะก็ทำเหมือนกับหน้า Index และส่วนสุดท้าย ก็คือการทำให้หน้า Index เวลาคลิกแล้ว เปลี่ยนมาที่หน้านี้ โดยการแก้ไขที่ href ของ Tag a ใน Template ของเรา ตอนที่แสดงรายการของโพส ในข้อ 7.2 จากโค๊ดประมาณนี้

<a class="post-link" href="blog-single.html">@entry.Title</a>

ให้เป็น

<a class="post-link" href="/blogs/@(entry.Id)">@entry.Title</a>

ซึ่งก็คือการสร้าง Link จากหน้า Index ไปยังหน้า Detail โดยตอนที่หน้าเว็บ ถูกแสดงผลในหน้า Browser จะเห็นว่า Url จะถูกเปลี่ยนเป็น /blogs/0 หรือ /blogs/1 ตามข้อมูลหลอกของเรา นั่นเอง

เท่านี้ หน้า Index ก็สามารถไปเรียกที่หน้า BlogDetail ตาม โพสที่เราเลือกได้แล้ว 

 

What's Next!?

ก่อนอื่น มาทบทวนกันหน่อยว่า ใน EP นี้ เราได้เรียนรู่้อะไรกันไปบ้าง?

  • เราได้รู้จักกับโค๊ด HTML และ C# เบื้องต้น ในระดับที่พอจะ Copy โค๊ดชาวบ้านเขาได้ อ่านโค๊ดง่ายๆ พอได้ และแก้โค๊ดชาวบ้านได้ (จาก บวกทีละ 1 เป็น บวกที่ละ 5)
  • เราได้รู้จักกับการใช้ CSS เบื้องต้น การเอาไฟล์ .css Link เข้ากับหน้าเว็บ HTML และโดยเฉพาะเรื่อง CSS Selector เราได้เห็นผลการใช้ CSS Selector จริงๆ ด้วย 1 ครั้ง กับ #blazor-error-ui
  • เราได้รู้จักกับ Path ว่าทำไมจะต้องใส่ / ไว้ข้างหน้า Path และมันต่่างจากไม่ใส่อย่างไร
  • เราได้รู้จักการสร้าง Class ในภาษา C# และการสร้าง Property ใน Class
  • เราได้รู้จักกับ List ว่า มันคือรายการของสิ่งที่เราสนใจ และเราได้ลองสร้างข้อมูล ใส่ลงไปใน List เป็นข้อมูลหลอกๆ อยู่ใน Source Code
  • เราได้ลอง Copy คำสั่ง for เพื่อใช้แสดงข้อมูลจาก List ในหน้าเว็บ
  • เราได้เจอกับ Bug ตัวแรกในชีวิต
  • เราได้เรียนรู้การส่ง Parameter หรือจะเรียกว่าตัวแปรก็ไม่ผิด ให้กับหน้าเว็บของเรา และวิธีการนำเอา Parameter นั้นมาใช้
  • เราได้เห็นการใช้งานคำสั่ง Where และ FirstOrDefault ร่วมกับ List
  • และสุดท้าย เราได้สร้าง Link จากหน้า Index ที่มีการส่ง Parameter ไปยังหน้า BlogDetail

เรี่ยนอะไรกันเยอะแยะเนี่ย!

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

เจอกันใน EP ต่อไปนะ

BLOG

LEVEL51 คือใคร?

เราเป็นบริษัทโน๊ตบุ้คของคนไทย ใช้เครื่องจากโรงงาน CLEVO แบบยี่ห้อดังในต่างประเทศ ที่คุณสามารถเลือกสเปคเองได้เกือบทั้งเครื่อง ถ้าโน๊ตบุ้คและคอมพิวเตอร์ของคุณ คืออุปกรณ์สำคัญในการทำงาน นี่คือเครื่องที่ออกแบบมาสำหรับคุณ

1317
Customers
0
THB 100,000 Builds
49
K
Average Build Price
0
K
Most Valuable Build

Our Government and Universities Customers:

Our Video Production, 3D Design, Software House Customers:

Landscape Design

Our Industrial and Construction Customers:

 

พิเศษเฉพาะคุณ - รับคูปองส่วนลด 2,000 บาท สำหรับการสั่งซื้อเครื่องกับเรา