บทความชุด .NET 6,7 แบบจับมือทำ — #6:Configuration
ด้วย IOption Pattern
ในบทความฉบับนี้ จะอธิบายถึงการอ่านค่า Configuration โดยใช้ standard ที่ Microsoft แนะนำ โดยมีเนื้อหาดังนี้
Configuration
Application Configuration ใน ASP.NET Core นั้นจะถูกจัดการมาจากการอ่าน Configuration Data ที่อยู่ในรูปแบบของ Key-Value Pairs จากหลายๆ Configuration Providers ดังนี้นะครับ.
- Settings files เช่น
appsettings.json
- Environment Variables
- Azure Key Vault
- Azure App Configuration
- Command-Line Arguments
- Custom Providers, Installed or Created
- Directory Files
- In-Memory .NET Objects
- App secrets (Secret Manager)
ในบทความนี้จะขอพูดถึงเฉพาะ Settings Files และ Environment Variables นะครับ ใครสนใจ Provider อื่นก็จิ้มลิ้งที่สนใจข้างบนได้เลยครับผม
IConfiguration
Microsoft ได้เตรียม Interface IConfiguration
เพื่อเป็นมาตราฐานในการเป็นศูนย์กลางเพื่อดึงข้อมูลจากหลายๆ Source มาแสดงผลนะครับ
ลำดับการดึงข้อมูลมาแสดงเป็น Configuration จะถูกเรียงดังนี้นะครับ (ลำดับที่น้อยกว่าจะถูกเขียนทับด้วยลำดับที่มากกว่านะครับ เช่น เรามี File appsettings.json
และมีการ Setup Environment Variables ไว้ ตัวแปร ที่ชื่อเดียวกันจาก appsettings.json
จะถูกแทนที่ด้วยตัวแปรจาก Environment Variables นะครับ
appsettings.json
appsettings.{Environment}.json
เช่นappsettings.Production.json
หรือappsettings.Development.json
นั้นจะอิงการอ่าน File จาก Environment VariableASPNETCORE_ENVIRONMENT
- Environment variables
- Command-line arguments
จาก File launchSetting.json
ซึ่งเป็นผลให้โปรแกรมทำการอ่าน File appsettings.Development.json ด้วย เพราะมี Environment = Development
Reference ลำดับการดึงข้อมูลนะคับ
จริงๆมีมากกว่านี้นะครับ ใครสนใจสามารถศึกษาเพิ่มเติมได้ที่นี้ครับผม
การดึงข้อมูลจาก appsettings.json
การดึงข้อมูลจาก Environment Variable
ตัวอย่าง appsettings.json
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
สามารถแปลงเป็น Environment Variables ได้ด้วยการใช้ __
มาเป็นตัวคั่นระหว่างชั้นของ Property ได้ดังนี้นะครับ
Windows Cmd
set Position__Title=Windows
set Position__Name=CMD
Bash
export Position__Title="Linux"
export Position__Name="Bash"
เมื่อเรา Setup Environment ตามข้างบนแล้ว ข้อมูลของ Configuration ก็จะถูก Override เมื่อเราสั่ง dotnet run
ดังนี้
- จาก appsettings.json -> Position:Title = “Editor”
- กลายมาเป็น Environment Variable -> Position__Title = “Windows” ใน Windows
- กลายมาเป็น Environment Variable -> Position__Title = “Linux” ใน Bash
Configuration — Options pattern
แต่ก่อนเราอาจจะ Hard Code String เพื่อให้สามารถเข้าถึง Configuration Item ได้
จะดีกว่าไหมถ้าเราสามารถอ้างอิงถึง Configuration Items ได้จาก Strong Type ครับ ซึ่ง Option Pattern ช่วยในเรื่องนี้ได้ครับ และยังช่วยให้เรามั่นใจได้ด้วยว่า Value ของ Configuration ของเราเป็น Type ไหน ไม่ต้องเจอ Error ที่ตอน Runtime จากการ Convert ครับ โดยในบทความนี้เราจะใช้ Pattern นี้ครับ
คุณสมบัติของ Class ที่จะเป็น Option Class
- ไม่เป็น Abstract Class
- เปิด Public Read-Write Properties สำหรับ Type จะถูก Bind กับ Configuration Item
ตัวอย่างการนำไปใช้งานนะครับ
ที่ Configure Service เราจะทำการระบุ Class ที่จะใช้ทำ Option Pattern แล้วหลังจากนั้นใน Class ไหนที่อยากจะใช้ Configuration Item เราก็สามารถใช้ Dependency Injection ในการ Inject Option Class เข้าไปที่ Constructure ได้เลยฮะ
ตัวอย่างการใช้ Option Pattern ในบทความนี้
คำถามที่อาจพบบ่อย (FAQ)
ขออนุญาตแอบแนะนำตัว ผมต้น นคร นะครับ Senior .NET Developer, ทักทายกันได้ที่
https://www.facebook.com/nakorn.rientrakrunchai
ผมได้รวบรวมคำถาม คำตอบที่เกิดขึ้น ระหว่างที่ผมได้ทดลองเขียน code ในหลายรูปแบบ และสรุปเผื่อท่านอื่นจะเจอแบบผม ดังนี้ นะครับ
สำหรับ source code ที่ผมใช้นำเสนอใน FAQ นี้ เพื่อนๆ ดูได้ที่นี่นะคับ
ถ้าไม่อยากใช้ลำดับของ Default Configuration ที่มีอยู่ จะทำใหม่ได้มั้ย
ได้คับ จัดไป, อ้างอิงตามเอกสาร Microsoft กันไปเลย
จากตัวอย่างโค๊ดข้างต้น ตรง configuration.Sources.Clear(); จะเป็นการเครีย Default Configuration แล้ว สร้างใหม่ ให้เอาเฉพาะ Json กันไปเลย โดยจะอ้างอิง ลำดับที่เขียนใน code ด้วยนะคับ อย่างไรก็ตาม ใน .NET 7 จะทำลักษณะ ตามตัวอย่าง นี้ครับ
ถ้าดูตามคอมเม้นสีเขียว ผมจะทำไว้สองแบบ แบบแรก ด้านบน กรอบฟ้า จะเป็นการ เพิ่ม Configuration เข้าไป จากอันเดิมที่มีอยู่ นะครับ,
โดยในการเพิ่มแบบนี้, ทาง Microsoft มีข้อพึงระวัง ดังนี้, ซึ่งมันหมายความว่า Configuration ที่เพิ่มเข้ามา, มันจะไป override ตัวที่มีอยู่แล้ว ถ้าตรงกัน
แบบที่สองคือ ล้าง ทำใหม่เลย คือแบบกรอบส้ม โค๊ดตรง builder.Configuration .Sources.Clear(); จะเป็นการล้างของเดิมออก แล้ว บรรทัดถัดๆมา จะเป็นการใส่เข้าไปใหม่ นะครับ
แล้วใน Console App/Unit test/อื่นๆ นอกจาก web api จะใช้ IConfiguration ได้อย่างไร
สำหรับ Console App, ทาง Microsoft มีคำแนะนำหลายแบบ แต่ผมเลือกแบบนี้ เพราะผมเข้าใจมันได้ง่ายครับ
ซึ่งเมื่อผมลองทำตาม ก็รันผ่านตาม Unit Test, โปรแกรมทำงานได้ปกติ นะคับ
แบบอื่นที่ Microsoft เขียนไว้ คือแบบใช้ hosting, ซึ่งน่าจะเหมาะกับงาน web api หรือ web app มากกว่า, เลยถ้าผมทำ Console App/Unit test/อื่นๆ ผมเลยจะไม่ได้ใช้ท่านี้ครับ
สามารถใช้ Enum มารับค่าจากใน IOption pattern ได้หรือไม่
เพื่อการใช้งานที่ง่าย ผมเลยเกิดคำถามกับตัวเองว่า มันใช้ Enum มารับค่าได้ไหม, จากที่ทดสอบ มันทำได้นะคับ โดยทำตามตัวอย่างนี้
ในกรอบแดง จะเป็นค่าใน appsettings.json, Option class และการใช้ IOption โดย DI ตามลำดับ, สำหรับสีฟ้า คือตัวอย่างการดึงค่า มาใช้ใน program.cs ตรงๆ
ภาพถัดมานี้ จะเป็นการดึงค่ามาใช้ที่ API Controller
ขอขอบคุณป้องกัน ที่สร้างบทความดีๆนี้ขึ้นมา และผมได้ทดลองอ่าน ใช้งาน และผลิต FAQ ขึ้นมา เพื่อเป็นประโยชน์ร่วมกัน, อย่างไรก็ตาม ยังมีอีกหลายบทความที่จะพาให้ทุกคน พัฒนาตัวเองในด้าน .NET ขึ้นมาได้ นะคับ
ลุยกันครับบบบ
- #0: เกริ่นนำ
- #1: ติดตั้งโปรแกรม
- #2: รวม Cheat Sheet
- #3: Empty Solution in GitHub
- #4: พัฒนาโครงสร้างของ Source Code
- #5: VS Code Debugging
- #6: Configuration
- #7: Dependency Injection & Service Lifetime
- #8: Domain Project
- #9: Core Project
- #10: Infra Project
- #11: API Project
- #12: Unit Testing
- #13: Logging and Monitoring
- #14:เพิ่มความปลอดภัยด้วย OAuth2 & OpenID Connect
- #15: Background Process & Scheduler
- #16: Health Checks
- #17: The Twelve-Factor App
- #18: Deployment — Docker
- #19: Deployment — Azure App Service
- #20: Deployment — Azure Container Apps