[{"data":1,"prerenderedAt":3095},["ShallowReactive",2],{"navigation_docs":3,"-phong-van-lo-trinh-ngay-5-aspnet-efcore":420,"-phong-van-lo-trinh-ngay-5-aspnet-efcore-surround":3090},[4,153],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Phỏng vấn .NET","i-lucide-briefcase","\u002Fphong-van","1.phong-van",[10,27,66,111,128],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":26},"Tổng quan","i-lucide-compass","\u002Fphong-van\u002Ftong-quan","1.phong-van\u002F1.tong-quan",[16,21],{"title":17,"path":18,"stem":19,"icon":20},"Thị trường HCM","\u002Fphong-van\u002Ftong-quan\u002Fthi-truong","1.phong-van\u002F1.tong-quan\u002F1.thi-truong","i-lucide-trending-up",{"title":22,"path":23,"stem":24,"icon":25},"Lộ trình 7 ngày","\u002Fphong-van\u002Ftong-quan\u002Flo-trinh","1.phong-van\u002F1.tong-quan\u002F2.lo-trinh","i-lucide-calendar-days",false,{"title":22,"icon":25,"path":28,"stem":29,"children":30,"page":26},"\u002Fphong-van\u002Flo-trinh","1.phong-van\u002F2.lo-trinh",[31,36,41,46,51,56,61],{"title":32,"path":33,"stem":34,"icon":35},"Ngày 1 — C# cơ bản","\u002Fphong-van\u002Flo-trinh\u002Fngay-1-csharp-co-ban","1.phong-van\u002F2.lo-trinh\u002F1.ngay-1-csharp-co-ban","i-lucide-1",{"title":37,"path":38,"stem":39,"icon":40},"Ngày 2 — OOP và SOLID","\u002Fphong-van\u002Flo-trinh\u002Fngay-2-oop-solid","1.phong-van\u002F2.lo-trinh\u002F2.ngay-2-oop-solid","i-lucide-2",{"title":42,"path":43,"stem":44,"icon":45},"Ngày 3 — C# nâng cao","\u002Fphong-van\u002Flo-trinh\u002Fngay-3-csharp-nang-cao","1.phong-van\u002F2.lo-trinh\u002F3.ngay-3-csharp-nang-cao","i-lucide-3",{"title":47,"path":48,"stem":49,"icon":50},"Ngày 4 — Database và SQL","\u002Fphong-van\u002Flo-trinh\u002Fngay-4-database-sql","1.phong-van\u002F2.lo-trinh\u002F4.ngay-4-database-sql","i-lucide-4",{"title":52,"path":53,"stem":54,"icon":55},"Ngày 5 — ASP.NET Core và EF Core","\u002Fphong-van\u002Flo-trinh\u002Fngay-5-aspnet-efcore","1.phong-van\u002F2.lo-trinh\u002F5.ngay-5-aspnet-efcore","i-lucide-5",{"title":57,"path":58,"stem":59,"icon":60},"Ngày 6 — DSA coding","\u002Fphong-van\u002Flo-trinh\u002Fngay-6-dsa","1.phong-van\u002F2.lo-trinh\u002F6.ngay-6-dsa","i-lucide-6",{"title":62,"path":63,"stem":64,"icon":65},"Ngày 7 — Mock và HR","\u002Fphong-van\u002Flo-trinh\u002Fngay-7-mock-interview","1.phong-van\u002F2.lo-trinh\u002F7.ngay-7-mock-interview","i-lucide-7",{"title":67,"icon":68,"path":69,"stem":70,"children":71,"page":26},"Ngân hàng câu hỏi","i-lucide-database","\u002Fphong-van\u002Fngan-hang-cau-hoi","1.phong-van\u002F3.ngan-hang-cau-hoi",[72,77,82,87,92,97,102,107],{"title":73,"path":74,"stem":75,"icon":76},"C# (60+ câu)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fcsharp","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F1.csharp","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"OOP và SOLID (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Foop","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F2.oop","i-lucide-shapes",{"title":83,"path":84,"stem":85,"icon":86},"SQL (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fsql","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F3.sql","i-lucide-database-zap",{"title":88,"path":89,"stem":90,"icon":91},"ASP.NET và EF (50+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-ef","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F4.aspnet-ef","i-lucide-server",{"title":93,"path":94,"stem":95,"icon":96},"DSA và Coding (30+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdsa-coding","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F5.dsa-coding","i-lucide-binary",{"title":98,"path":99,"stem":100,"icon":101},"HR và Soft skill (25+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fhr-behavior","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F6.hr-behavior","i-lucide-users",{"title":103,"path":104,"stem":105,"icon":106},"Design Pattern (55+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdesign-pattern","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F7.design-pattern","i-lucide-puzzle",{"title":108,"path":109,"stem":110,"icon":91},"ASP.NET MVC và Web API","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-mvc-webapi","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F8.aspnet-mvc-webapi",{"title":112,"itle":113,"icon":114,"path":115,"stem":116,"children":117,"page":26},"Tai Lieu","Tài liệu và Cheat sheet","i-lucide-book-marked","\u002Fphong-van\u002Ftai-lieu","1.phong-van\u002F4.tai-lieu",[118,123],{"title":119,"path":120,"stem":121,"icon":122},"Cheat Sheet","\u002Fphong-van\u002Ftai-lieu\u002Fcheatsheet","1.phong-van\u002F4.tai-lieu\u002F1.cheatsheet","i-lucide-clipboard-list",{"title":124,"path":125,"stem":126,"icon":127},"Nguồn tham khảo","\u002Fphong-van\u002Ftai-lieu\u002Fnguon","1.phong-van\u002F4.tai-lieu\u002F2.nguon","i-lucide-link",{"title":129,"icon":130,"path":131,"stem":132,"children":133,"page":26},"Phỏng vấn English","i-lucide-globe","\u002Fphong-van\u002Fenglish-interview","1.phong-van\u002F5.english-interview",[134,138,143,148],{"title":135,"path":136,"stem":137,"icon":130},"Tổng quan English","\u002Fphong-van\u002Fenglish-interview\u002Ftong-quan","1.phong-van\u002F5.english-interview\u002F1.tong-quan",{"title":139,"path":140,"stem":141,"icon":142},"Vocabulary","\u002Fphong-van\u002Fenglish-interview\u002Fvocabulary","1.phong-van\u002F5.english-interview\u002F2.vocabulary","i-lucide-book-a",{"title":144,"path":145,"stem":146,"icon":147},"Technical Q và A (EN)","\u002Fphong-van\u002Fenglish-interview\u002Ftechnical-en","1.phong-van\u002F5.english-interview\u002F3.technical-en","i-lucide-code",{"title":149,"path":150,"stem":151,"icon":152},"Behavioral (EN)","\u002Fphong-van\u002Fenglish-interview\u002Fbehavioral-en","1.phong-van\u002F5.english-interview\u002F4.behavioral-en","i-lucide-message-square-text",{"title":154,"icon":155,"path":156,"stem":157,"children":158},"Tự học","i-lucide-graduation-cap","\u002Ftu-hoc","2.tu-hoc",[159,161,287,310,333,357,384],{"title":154,"path":156,"stem":160,"icon":155},"2.tu-hoc\u002Findex",{"title":162,"icon":68,"path":163,"stem":164,"children":165},"Database","\u002Ftu-hoc\u002Fdatabase","2.tu-hoc\u002F1.database\u002Findex",[166,167,197,222,243,248],{"title":162,"path":163,"stem":164,"icon":68},{"title":168,"icon":91,"path":169,"stem":170,"children":171,"page":26},"SQL Server","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server","2.tu-hoc\u002F1.database\u002F2.sql-server",[172,177,182,187,192],{"title":173,"path":174,"stem":175,"icon":176},"1. Giới thiệu và Cài đặt","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F1.gioi-thieu-cai-dat","i-lucide-play-circle",{"title":178,"path":179,"stem":180,"icon":181},"2. Cú pháp cơ bản","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F2.cu-phap-co-ban","i-lucide-code-2",{"title":183,"path":184,"stem":185,"icon":186},"3. Truy vấn nâng cao","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F3.truy-van-nang-cao","i-lucide-git-merge",{"title":188,"path":189,"stem":190,"icon":191},"4. Đặc thù và Performance","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F4.dac-thu-performance","i-lucide-gauge",{"title":193,"path":194,"stem":195,"icon":196},"5. Q và A phỏng vấn","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F5.cau-hoi-phong-van","i-lucide-message-circle-question",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":26},"PostgreSQL","i-simple-icons-postgresql","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql","2.tu-hoc\u002F1.database\u002F3.postgresql",[203,206,209,212,215,218],{"title":173,"path":204,"stem":205,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":207,"stem":208,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F2.cu-phap-co-ban",{"title":183,"path":210,"stem":211,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F3.truy-van-nang-cao",{"title":188,"path":213,"stem":214,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F4.dac-thu-performance",{"title":193,"path":216,"stem":217,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F5.cau-hoi-phong-van",{"title":219,"path":220,"stem":221,"icon":96},"6. Tích hợp C# và Postgres","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftich-hop-csharp","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F6.tich-hop-csharp",{"title":223,"icon":224,"path":225,"stem":226,"children":227,"page":26},"MySQL","i-simple-icons-mysql","\u002Ftu-hoc\u002Fdatabase\u002Fmysql","2.tu-hoc\u002F1.database\u002F4.mysql",[228,231,234,237,240],{"title":173,"path":229,"stem":230,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F4.mysql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":232,"stem":233,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F4.mysql\u002F2.cu-phap-co-ban",{"title":183,"path":235,"stem":236,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F4.mysql\u002F3.truy-van-nang-cao",{"title":188,"path":238,"stem":239,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F4.mysql\u002F4.dac-thu-performance",{"title":193,"path":241,"stem":242,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F4.mysql\u002F5.cau-hoi-phong-van",{"title":244,"path":245,"stem":246,"icon":247},"So sánh 3 RDBMS","\u002Ftu-hoc\u002Fdatabase\u002Fso-sanh","2.tu-hoc\u002F1.database\u002F5.so-sanh","i-lucide-columns-3",{"title":249,"path":250,"stem":251,"children":252,"icon":254},"Supabase (BaaS)","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002Findex",[253,255,259,264,269,274,278,283],{"title":249,"path":250,"stem":251,"icon":254},"i-simple-icons-supabase",{"title":256,"path":257,"stem":258,"icon":68},"1. Database","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fdatabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002F1.database",{"title":260,"path":261,"stem":262,"icon":263},"2. Authentication","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fauthentication","2.tu-hoc\u002F1.database\u002F6.supabase\u002F2.authentication","i-lucide-key",{"title":265,"path":266,"stem":267,"icon":268},"3. Storage & Realtime","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fstorage-realtime","2.tu-hoc\u002F1.database\u002F6.supabase\u002F3.storage-realtime","i-lucide-zap",{"title":270,"path":271,"stem":272,"icon":273},"4. Edge Functions & AI","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Ffunctions-ai","2.tu-hoc\u002F1.database\u002F6.supabase\u002F4.functions-ai","i-lucide-brain",{"title":275,"path":276,"stem":277,"icon":181},"5. API & SDKs","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fapi-sdk","2.tu-hoc\u002F1.database\u002F6.supabase\u002F5.api-sdk",{"title":279,"path":280,"stem":281,"icon":282},"6. Platform & Deploy","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fplatform-deploy","2.tu-hoc\u002F1.database\u002F6.supabase\u002F6.platform-deploy","i-lucide-cloud",{"title":284,"path":285,"stem":286,"icon":196},"7. Interview & Q&A","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Finterview","2.tu-hoc\u002F1.database\u002F6.supabase\u002F7.interview",{"title":288,"icon":289,"path":290,"stem":291,"children":292},"TypeScript","i-simple-icons-typescript","\u002Ftu-hoc\u002Ftypescript","2.tu-hoc\u002F2.typescript\u002Findex",[293,294,297,301,306],{"title":288,"path":290,"stem":291,"icon":289},{"title":173,"path":295,"stem":296,"icon":176},"\u002Ftu-hoc\u002Ftypescript\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F2.typescript\u002F1.gioi-thieu-cai-dat",{"title":298,"path":299,"stem":300,"icon":81},"2. Type System","\u002Ftu-hoc\u002Ftypescript\u002Ftype-system","2.tu-hoc\u002F2.typescript\u002F2.type-system",{"title":302,"path":303,"stem":304,"icon":305},"3. Advanced types","\u002Ftu-hoc\u002Ftypescript\u002Fadvanced-types","2.tu-hoc\u002F2.typescript\u002F3.advanced-types","i-lucide-braces",{"title":307,"path":308,"stem":309,"icon":196},"4. Q và A phỏng vấn","\u002Ftu-hoc\u002Ftypescript\u002Fcau-hoi-phong-van","2.tu-hoc\u002F2.typescript\u002F4.cau-hoi-phong-van",{"title":311,"icon":81,"path":312,"stem":313,"children":314},"OOP","\u002Ftu-hoc\u002Foop","2.tu-hoc\u002F3.oop\u002Findex",[315,316,321,326,330],{"title":311,"path":312,"stem":313,"icon":81},{"title":317,"path":318,"stem":319,"icon":320},"1. Bốn tính chất","\u002Ftu-hoc\u002Foop\u002F4-tinh-chat","2.tu-hoc\u002F3.oop\u002F1.4-tinh-chat","i-lucide-circle-dot",{"title":322,"path":323,"stem":324,"icon":325},"2. SOLID","\u002Ftu-hoc\u002Foop\u002Fsolid","2.tu-hoc\u002F3.oop\u002F2.solid","i-lucide-shield",{"title":327,"path":328,"stem":329,"icon":106},"3. Design Pattern","\u002Ftu-hoc\u002Foop\u002Fdesign-pattern","2.tu-hoc\u002F3.oop\u002F3.design-pattern",{"title":307,"path":331,"stem":332,"icon":196},"\u002Ftu-hoc\u002Foop\u002Fcau-hoi-phong-van","2.tu-hoc\u002F3.oop\u002F4.cau-hoi-phong-van",{"title":334,"icon":305,"path":335,"stem":336,"children":337},"Generic","\u002Ftu-hoc\u002Fgeneric","2.tu-hoc\u002F4.generic\u002Findex",[338,339,344,349,354],{"title":334,"path":335,"stem":336,"icon":305},{"title":340,"path":341,"stem":342,"icon":343},"1. Khái niệm và cú pháp","\u002Ftu-hoc\u002Fgeneric\u002Fkhai-niem","2.tu-hoc\u002F4.generic\u002F1.khai-niem","i-lucide-book",{"title":345,"path":346,"stem":347,"icon":348},"2. Constraint và Variance","\u002Ftu-hoc\u002Fgeneric\u002Fconstraint-variance","2.tu-hoc\u002F4.generic\u002F2.constraint-variance","i-lucide-filter",{"title":350,"path":351,"stem":352,"icon":353},"3. C# vs TS","\u002Ftu-hoc\u002Fgeneric\u002Fso-sanh","2.tu-hoc\u002F4.generic\u002F3.so-sanh","i-lucide-git-compare",{"title":307,"path":355,"stem":356,"icon":196},"\u002Ftu-hoc\u002Fgeneric\u002Fcau-hoi-phong-van","2.tu-hoc\u002F4.generic\u002F4.cau-hoi-phong-van",{"title":358,"icon":359,"path":360,"stem":361,"children":362},"Nuxt 4","i-simple-icons-nuxt","\u002Ftu-hoc\u002Fnuxt-4","2.tu-hoc\u002F5.nuxt-4\u002Findex",[363,364,367,372,376,379],{"title":358,"path":360,"stem":361,"icon":359},{"title":173,"path":365,"stem":366,"icon":176},"\u002Ftu-hoc\u002Fnuxt-4\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F5.nuxt-4\u002F1.gioi-thieu-cai-dat",{"title":368,"path":369,"stem":370,"icon":371},"2. Routing và Rendering","\u002Ftu-hoc\u002Fnuxt-4\u002Frouting-rendering","2.tu-hoc\u002F5.nuxt-4\u002F2.routing-rendering","i-lucide-route",{"title":373,"path":374,"stem":375,"icon":91},"3. Data và Server","\u002Ftu-hoc\u002Fnuxt-4\u002Fdata-server","2.tu-hoc\u002F5.nuxt-4\u002F3.data-server",{"title":307,"path":377,"stem":378,"icon":196},"\u002Ftu-hoc\u002Fnuxt-4\u002Fcau-hoi-phong-van","2.tu-hoc\u002F5.nuxt-4\u002F4.cau-hoi-phong-van",{"title":380,"path":381,"stem":382,"icon":383},"5. Practical Todo App","\u002Ftu-hoc\u002Fnuxt-4\u002Fpractical-todo-app","2.tu-hoc\u002F5.nuxt-4\u002F5.practical-todo-app","i-lucide-check-square",{"title":385,"path":386,"stem":387,"children":388,"icon":390},"Tailwind CSS","\u002Ftu-hoc\u002Ftailwindcss","2.tu-hoc\u002F6.tailwindcss\u002Findex",[389,391,396,401,406,411,416],{"title":385,"path":386,"stem":387,"icon":390},"i-simple-icons-tailwindcss",{"title":392,"path":393,"stem":394,"icon":395},"1. Layout & Spacing","\u002Ftu-hoc\u002Ftailwindcss\u002Flayout-spacing","2.tu-hoc\u002F6.tailwindcss\u002F1.layout-spacing","i-lucide-layout",{"title":397,"path":398,"stem":399,"icon":400},"2. Typography & Colors","\u002Ftu-hoc\u002Ftailwindcss\u002Ftypography-colors","2.tu-hoc\u002F6.tailwindcss\u002F2.typography-colors","i-lucide-type",{"title":402,"path":403,"stem":404,"icon":405},"3. Interactive & Effects","\u002Ftu-hoc\u002Ftailwindcss\u002Finteractive-effects","2.tu-hoc\u002F6.tailwindcss\u002F3.interactive-effects","i-lucide-sparkles",{"title":407,"path":408,"stem":409,"icon":410},"4. Responsive & Dark Mode","\u002Ftu-hoc\u002Ftailwindcss\u002Fresponsive-darkmode","2.tu-hoc\u002F6.tailwindcss\u002F4.responsive-darkmode","i-lucide-monitor-smartphone",{"title":412,"path":413,"stem":414,"icon":415},"5. Customization & Theme","\u002Ftu-hoc\u002Ftailwindcss\u002Fcustomization","2.tu-hoc\u002F6.tailwindcss\u002F5.customization","i-lucide-settings-2",{"title":417,"path":418,"stem":419,"icon":181},"6. Practical Projects","\u002Ftu-hoc\u002Ftailwindcss\u002Fpractical-projects","2.tu-hoc\u002F6.tailwindcss\u002F6.practical-projects",{"id":421,"title":52,"body":422,"description":3083,"extension":3084,"links":3085,"meta":3086,"navigation":3087,"path":53,"seo":3088,"stem":54,"__hash__":3089},"docs\u002F1.phong-van\u002F2.lo-trinh\u002F5.ngay-5-aspnet-efcore.md",{"type":423,"value":424,"toc":3040},"minimark",[425,430,434,488,494,497,501,506,517,539,547,734,738,893,897,938,951,1016,1018,1022,1026,1045,1065,1069,1126,1130,1247,1251,1322,1329,1333,1394,1396,1400,1404,1505,1520,1524,1530,1534,1694,1698,1872,1880,1894,1899,1929,1931,1935,1939,1945,1950,1975,1979,2076,2080,2169,2173,2212,2214,2218,2222,2312,2316,2378,2417,2421,2455,2466,2470,2475,2517,2524,2528,2558,2562,2581,2585,2634,2638,2732,2736,2859,2885,2889,2952,2954,2958,3020,3029,3031,3036],[426,427,429],"h2",{"id":428},"mục-tiêu-ngày-5","Mục tiêu ngày 5",[431,432,433],"p",{},"Sau ngày 5 bạn phải:",[435,436,437,446,457,464,471,478],"ul",{},[438,439,440,441,445],"li",{},"Trace được ",[442,443,444],"strong",{},"HTTP request đi qua middleware pipeline"," ra sao.",[438,447,448,449,452,453,456],{},"Phân biệt ",[442,450,451],{},"3 DI lifetimes"," + hiểu ",[442,454,455],{},"captive dependency",".",[438,458,459,460,463],{},"Thiết kế ",[442,461,462],{},"REST API"," đúng convention + JWT auth.",[438,465,466,467,470],{},"Hiểu ",[442,468,469],{},"EF Core change tracking"," ở mức cơ chế.",[438,472,473,474,477],{},"Demo được ",[442,475,476],{},"N+1 problem"," và 4 cách fix.",[438,479,480,481,484,485,456],{},"Biết khi nào dùng ",[442,482,483],{},"Migration"," vs ",[442,486,487],{},"Database-first",[489,490,493],"callout",{"color":491,"icon":492},"primary","i-lucide-info","🟢 Intern | 🔵 Junior | 🟡 Mid | 🔴 Senior",[495,496],"hr",{},[426,498,500],{"id":499},"_1-kiến-trúc-aspnet-core","1. Kiến trúc ASP.NET Core",[502,503,505],"h3",{"id":504},"_11-hành-trình-của-1-http-request","1.1. Hành trình của 1 HTTP request",[507,508,513],"pre",{"className":509,"code":511,"language":512},[510],"language-text","Client (Browser\u002FPostman)\n    │\n    ▼ HTTP Request\n┌────────────────────────────┐\n│ Kestrel (web server)       │  ← lắng nghe port 5000\u002F5001\n└────────────────────────────┘\n    │\n    ▼\n┌────────────────────────────┐\n│ Middleware Pipeline        │  ← thứ tự QUAN TRỌNG\n│ ┌──────────────────────┐   │\n│ │ Exception handler    │   │  ← bao quanh toàn pipeline\n│ │ ┌──────────────────┐ │   │\n│ │ │ HTTPS redirect   │ │   │\n│ │ │ ┌──────────────┐ │ │   │\n│ │ │ │ Routing      │ │ │   │\n│ │ │ │ ┌──────────┐ │ │ │   │\n│ │ │ │ │ Auth     │ │ │ │   │\n│ │ │ │ │ ┌──────┐ │ │ │ │   │\n│ │ │ │ │ │Authz │ │ │ │ │   │\n│ │ │ │ │ │ ┌──┐ │ │ │ │ │   │\n│ │ │ │ │ │ │EP│ │ │ │ │ │   │  ← endpoint (controller action)\n│ │ │ │ │ │ └──┘ │ │ │ │ │   │\n│ │ │ │ │ └──────┘ │ │ │ │   │\n│ │ │ │ └──────────┘ │ │ │   │\n│ │ │ └──────────────┘ │ │   │\n│ │ └──────────────────┘ │   │\n│ └──────────────────────┘   │\n└────────────────────────────┘\n    │\n    ▼ HTTP Response\nClient\n","text",[514,515,511],"code",{"__ignoreMap":516},"",[489,518,519,520,523,524,528,529,532,533,535,536,456],{"color":491,"icon":492},"🔵 Mỗi middleware là ",[442,521,522],{},"bánh sandwich",": làm gì đó ",[525,526,527],"em",{},"trước"," ",[514,530,531],{},"next",", gọi ",[514,534,531],{},", làm gì đó ",[525,537,538],{},"sau",[502,540,542,543,546],{"id":541},"_12-programcs-chuẩn-net-89","1.2. ",[514,544,545],{},"Program.cs"," chuẩn .NET 8\u002F9",[507,548,552],{"className":549,"code":550,"language":551,"meta":516,"style":516},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","var builder = WebApplication.CreateBuilder(args);\n\n\u002F\u002F === 1. SERVICES (DI registration) — register ở đây ===\nbuilder.Services.AddControllers();\nbuilder.Services.AddDbContext\u003CAppDbContext>(opt =>\n    opt.UseSqlServer(builder.Configuration.GetConnectionString(\"Default\")));\nbuilder.Services.AddScoped\u003CIUserService, UserService>();\nbuilder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n    .AddJwtBearer(opt => { \u002F* config JWT *\u002F });\nbuilder.Services.AddAuthorization();\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\nvar app = builder.Build();\n\n\u002F\u002F === 2. MIDDLEWARE PIPELINE — thứ tự QUAN TRỌNG ===\nif (app.Environment.IsDevelopment()) {\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\napp.UseExceptionHandler(\"\u002Ferror\");      \u002F\u002F 1. Catch exception trong pipeline\napp.UseHttpsRedirection();              \u002F\u002F 2. HTTP → HTTPS\napp.UseStaticFiles();                   \u002F\u002F 3. Serve wwwroot\u002F\napp.UseRouting();                       \u002F\u002F 4. Match route\napp.UseCors(\"default\");                 \u002F\u002F 5. CORS check\napp.UseAuthentication();                \u002F\u002F 6. Verify token → ClaimsPrincipal\napp.UseAuthorization();                 \u002F\u002F 7. Check roles\u002Fpolicies\napp.MapControllers();                   \u002F\u002F 8. Run endpoint\n\napp.Run();\n","csharp",[514,553,554,562,569,575,581,587,593,599,605,611,617,623,629,634,640,645,651,657,663,669,675,681,687,693,699,705,711,717,723,728],{"__ignoreMap":516},[555,556,559],"span",{"class":557,"line":558},"line",1,[555,560,561],{},"var builder = WebApplication.CreateBuilder(args);\n",[555,563,565],{"class":557,"line":564},2,[555,566,568],{"emptyLinePlaceholder":567},true,"\n",[555,570,572],{"class":557,"line":571},3,[555,573,574],{},"\u002F\u002F === 1. SERVICES (DI registration) — register ở đây ===\n",[555,576,578],{"class":557,"line":577},4,[555,579,580],{},"builder.Services.AddControllers();\n",[555,582,584],{"class":557,"line":583},5,[555,585,586],{},"builder.Services.AddDbContext\u003CAppDbContext>(opt =>\n",[555,588,590],{"class":557,"line":589},6,[555,591,592],{},"    opt.UseSqlServer(builder.Configuration.GetConnectionString(\"Default\")));\n",[555,594,596],{"class":557,"line":595},7,[555,597,598],{},"builder.Services.AddScoped\u003CIUserService, UserService>();\n",[555,600,602],{"class":557,"line":601},8,[555,603,604],{},"builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n",[555,606,608],{"class":557,"line":607},9,[555,609,610],{},"    .AddJwtBearer(opt => { \u002F* config JWT *\u002F });\n",[555,612,614],{"class":557,"line":613},10,[555,615,616],{},"builder.Services.AddAuthorization();\n",[555,618,620],{"class":557,"line":619},11,[555,621,622],{},"builder.Services.AddEndpointsApiExplorer();\n",[555,624,626],{"class":557,"line":625},12,[555,627,628],{},"builder.Services.AddSwaggerGen();\n",[555,630,632],{"class":557,"line":631},13,[555,633,568],{"emptyLinePlaceholder":567},[555,635,637],{"class":557,"line":636},14,[555,638,639],{},"var app = builder.Build();\n",[555,641,643],{"class":557,"line":642},15,[555,644,568],{"emptyLinePlaceholder":567},[555,646,648],{"class":557,"line":647},16,[555,649,650],{},"\u002F\u002F === 2. MIDDLEWARE PIPELINE — thứ tự QUAN TRỌNG ===\n",[555,652,654],{"class":557,"line":653},17,[555,655,656],{},"if (app.Environment.IsDevelopment()) {\n",[555,658,660],{"class":557,"line":659},18,[555,661,662],{},"    app.UseSwagger();\n",[555,664,666],{"class":557,"line":665},19,[555,667,668],{},"    app.UseSwaggerUI();\n",[555,670,672],{"class":557,"line":671},20,[555,673,674],{},"}\n",[555,676,678],{"class":557,"line":677},21,[555,679,680],{},"app.UseExceptionHandler(\"\u002Ferror\");      \u002F\u002F 1. Catch exception trong pipeline\n",[555,682,684],{"class":557,"line":683},22,[555,685,686],{},"app.UseHttpsRedirection();              \u002F\u002F 2. HTTP → HTTPS\n",[555,688,690],{"class":557,"line":689},23,[555,691,692],{},"app.UseStaticFiles();                   \u002F\u002F 3. Serve wwwroot\u002F\n",[555,694,696],{"class":557,"line":695},24,[555,697,698],{},"app.UseRouting();                       \u002F\u002F 4. Match route\n",[555,700,702],{"class":557,"line":701},25,[555,703,704],{},"app.UseCors(\"default\");                 \u002F\u002F 5. CORS check\n",[555,706,708],{"class":557,"line":707},26,[555,709,710],{},"app.UseAuthentication();                \u002F\u002F 6. Verify token → ClaimsPrincipal\n",[555,712,714],{"class":557,"line":713},27,[555,715,716],{},"app.UseAuthorization();                 \u002F\u002F 7. Check roles\u002Fpolicies\n",[555,718,720],{"class":557,"line":719},28,[555,721,722],{},"app.MapControllers();                   \u002F\u002F 8. Run endpoint\n",[555,724,726],{"class":557,"line":725},29,[555,727,568],{"emptyLinePlaceholder":567},[555,729,731],{"class":557,"line":730},30,[555,732,733],{},"app.Run();\n",[502,735,737],{"id":736},"_13-custom-middleware-viết-tay","1.3. 🟡 Custom Middleware — viết tay",[507,739,741],{"className":549,"code":740,"language":551,"meta":516,"style":516},"public class RequestTimingMiddleware {\n    private readonly RequestDelegate _next;\n    private readonly ILogger\u003CRequestTimingMiddleware> _logger;\n    \n    public RequestTimingMiddleware(\n        RequestDelegate next,\n        ILogger\u003CRequestTimingMiddleware> logger) {\n        _next = next;\n        _logger = logger;\n    }\n    \n    public async Task InvokeAsync(HttpContext context) {\n        var sw = Stopwatch.StartNew();\n        \n        \u002F\u002F BEFORE next\n        _logger.LogInformation(\"→ {Method} {Path}\",\n            context.Request.Method, context.Request.Path);\n        \n        await _next(context);     \u002F\u002F gọi middleware tiếp theo\n        \n        \u002F\u002F AFTER next\n        sw.Stop();\n        _logger.LogInformation(\"← {Path} {Status} in {Ms}ms\",\n            context.Request.Path,\n            context.Response.StatusCode,\n            sw.ElapsedMilliseconds);\n    }\n}\n\n\u002F\u002F Register\napp.UseMiddleware\u003CRequestTimingMiddleware>();\n",[514,742,743,748,753,758,763,768,773,778,783,788,793,797,802,807,812,817,822,827,831,836,840,845,850,855,860,865,870,874,878,882,887],{"__ignoreMap":516},[555,744,745],{"class":557,"line":558},[555,746,747],{},"public class RequestTimingMiddleware {\n",[555,749,750],{"class":557,"line":564},[555,751,752],{},"    private readonly RequestDelegate _next;\n",[555,754,755],{"class":557,"line":571},[555,756,757],{},"    private readonly ILogger\u003CRequestTimingMiddleware> _logger;\n",[555,759,760],{"class":557,"line":577},[555,761,762],{},"    \n",[555,764,765],{"class":557,"line":583},[555,766,767],{},"    public RequestTimingMiddleware(\n",[555,769,770],{"class":557,"line":589},[555,771,772],{},"        RequestDelegate next,\n",[555,774,775],{"class":557,"line":595},[555,776,777],{},"        ILogger\u003CRequestTimingMiddleware> logger) {\n",[555,779,780],{"class":557,"line":601},[555,781,782],{},"        _next = next;\n",[555,784,785],{"class":557,"line":607},[555,786,787],{},"        _logger = logger;\n",[555,789,790],{"class":557,"line":613},[555,791,792],{},"    }\n",[555,794,795],{"class":557,"line":619},[555,796,762],{},[555,798,799],{"class":557,"line":625},[555,800,801],{},"    public async Task InvokeAsync(HttpContext context) {\n",[555,803,804],{"class":557,"line":631},[555,805,806],{},"        var sw = Stopwatch.StartNew();\n",[555,808,809],{"class":557,"line":636},[555,810,811],{},"        \n",[555,813,814],{"class":557,"line":642},[555,815,816],{},"        \u002F\u002F BEFORE next\n",[555,818,819],{"class":557,"line":647},[555,820,821],{},"        _logger.LogInformation(\"→ {Method} {Path}\",\n",[555,823,824],{"class":557,"line":653},[555,825,826],{},"            context.Request.Method, context.Request.Path);\n",[555,828,829],{"class":557,"line":659},[555,830,811],{},[555,832,833],{"class":557,"line":665},[555,834,835],{},"        await _next(context);     \u002F\u002F gọi middleware tiếp theo\n",[555,837,838],{"class":557,"line":671},[555,839,811],{},[555,841,842],{"class":557,"line":677},[555,843,844],{},"        \u002F\u002F AFTER next\n",[555,846,847],{"class":557,"line":683},[555,848,849],{},"        sw.Stop();\n",[555,851,852],{"class":557,"line":689},[555,853,854],{},"        _logger.LogInformation(\"← {Path} {Status} in {Ms}ms\",\n",[555,856,857],{"class":557,"line":695},[555,858,859],{},"            context.Request.Path,\n",[555,861,862],{"class":557,"line":701},[555,863,864],{},"            context.Response.StatusCode,\n",[555,866,867],{"class":557,"line":707},[555,868,869],{},"            sw.ElapsedMilliseconds);\n",[555,871,872],{"class":557,"line":713},[555,873,792],{},[555,875,876],{"class":557,"line":719},[555,877,674],{},[555,879,880],{"class":557,"line":725},[555,881,568],{"emptyLinePlaceholder":567},[555,883,884],{"class":557,"line":730},[555,885,886],{},"\u002F\u002F Register\n",[555,888,890],{"class":557,"line":889},31,[555,891,892],{},"app.UseMiddleware\u003CRequestTimingMiddleware>();\n",[502,894,896],{"id":895},"_14-bẫy-thứ-tự-middleware","1.4. 🔴 Bẫy thứ tự middleware",[489,898,901,908,921,932],{"color":899,"icon":900},"error","i-lucide-alert-octagon",[431,902,903,904,907],{},"⭐ ",[442,905,906],{},"PV thường hỏi:"," thứ tự sai gây bug gì?",[431,909,910,528,913,916,917,920],{},[442,911,912],{},"Sai:",[514,914,915],{},"UseAuthorization()"," trước ",[514,918,919],{},"UseAuthentication()"," →",[435,922,923,926,929],{},[438,924,925],{},"Authorization check role trong ClaimsPrincipal.",[438,927,928],{},"Nhưng Authentication chưa populate ClaimsPrincipal.",[438,930,931],{},"→ User luôn unauthorized dù có token đúng.",[431,933,934,937],{},[442,935,936],{},"Đúng",": Routing → CORS → Authentication → Authorization → Endpoints.",[502,939,941,942,484,945,484,948],{"id":940},"_15-use-vs-run-vs-map","1.5. ",[514,943,944],{},"Use",[514,946,947],{},"Run",[514,949,950],{},"Map",[952,953,954,966],"table",{},[955,956,957],"thead",{},[958,959,960,963],"tr",{},[961,962],"th",{},[961,964,965],{},"Tác dụng",[967,968,969,983,996,1006],"tbody",{},[958,970,971,977],{},[972,973,974],"td",{},[514,975,976],{},"app.Use(...)",[972,978,979,980,982],{},"Middleware có ",[514,981,531],{}," — chuyển control",[958,984,985,990],{},[972,986,987],{},[514,988,989],{},"app.Run(...)",[972,991,992,995],{},[442,993,994],{},"Terminal"," middleware — không gọi next",[958,997,998,1003],{},[972,999,1000],{},[514,1001,1002],{},"app.Map(\"\u002Fpath\", ...)",[972,1004,1005],{},"Branch pipeline theo path",[958,1007,1008,1013],{},[972,1009,1010],{},[514,1011,1012],{},"app.MapWhen(predicate, ...)",[972,1014,1015],{},"Branch theo điều kiện",[495,1017],{},[426,1019,1021],{"id":1020},"_2-dependency-injection-sâu","2. Dependency Injection — sâu",[502,1023,1025],{"id":1024},"_21-3-lifetimes","2.1. 3 lifetimes",[1027,1028,1029,1035,1040],"field-group",{},[1030,1031,1034],"field",{"name":1032,"type":1033},"Singleton","1 instance \u002F app","Tạo 1 lần khi register hoặc lần đầu inject. Share toàn app. Dùng cho stateless service, cache, logger, config.",[1030,1036,1039],{"name":1037,"type":1038},"Scoped","1 instance \u002F request","Mỗi HTTP request → 1 instance mới. Dispose cuối request. Dùng cho DbContext, repository, current-user service.",[1030,1041,1044],{"name":1042,"type":1043},"Transient","Mỗi inject mới","Tạo instance mới mỗi lần inject. Stateless helper nhẹ.",[507,1046,1048],{"className":549,"code":1047,"language":551,"meta":516,"style":516},"builder.Services.AddSingleton\u003CICache, MemoryCache>();\nbuilder.Services.AddScoped\u003CIOrderService, OrderService>();\nbuilder.Services.AddTransient\u003CIEmailFormatter, EmailFormatter>();\n",[514,1049,1050,1055,1060],{"__ignoreMap":516},[555,1051,1052],{"class":557,"line":558},[555,1053,1054],{},"builder.Services.AddSingleton\u003CICache, MemoryCache>();\n",[555,1056,1057],{"class":557,"line":564},[555,1058,1059],{},"builder.Services.AddScoped\u003CIOrderService, OrderService>();\n",[555,1061,1062],{"class":557,"line":571},[555,1063,1064],{},"builder.Services.AddTransient\u003CIEmailFormatter, EmailFormatter>();\n",[502,1066,1068],{"id":1067},"_22-vì-sao-dbcontext-nên-scoped","2.2. Vì sao DbContext nên Scoped?",[489,1070,1072,1087,1098,1104],{"color":1071,"icon":268},"warning",[431,1073,1074,1075,1078,1079,1082,1083,1086],{},"🟡 ",[442,1076,1077],{},"DbContext"," = ",[442,1080,1081],{},"Unit of Work"," + ",[442,1084,1085],{},"Repository facade",":",[435,1088,1089,1092],{},[438,1090,1091],{},"Track changes của entity.",[438,1093,1094,1097],{},[514,1095,1096],{},"SaveChanges()"," = commit 1 transaction.",[431,1099,1100,1103],{},[442,1101,1102],{},"Phải Scoped"," vì:",[1105,1106,1107,1113,1119],"ol",{},[438,1108,1109,1112],{},[442,1110,1111],{},"Không thread-safe"," — không share giữa request.",[438,1114,1115,1118],{},[442,1116,1117],{},"Unit of Work scope"," = 1 request = 1 transaction logic.",[438,1120,1121,1122,1125],{},"Phải ",[442,1123,1124],{},"Dispose"," cuối request (giải phóng connection).",[502,1127,1129],{"id":1128},"_23-captive-dependency","2.3. 🔴 Captive Dependency",[489,1131,1132,1140,1152,1186,1195],{"color":899,"icon":900},[431,1133,903,1134,528,1137],{},[442,1135,1136],{},"Câu PV nâng cao:",[525,1138,1139],{},"\"Captive Dependency là gì?\"",[431,1141,1142,1145,1146,1148,1149,1151],{},[442,1143,1144],{},"Vấn đề:"," Inject ",[442,1147,1037],{}," vào ",[442,1150,1032],{}," → Singleton ôm Scoped đầu tiên mãi mãi.",[507,1153,1155],{"className":549,"code":1154,"language":551,"meta":516,"style":516},"\u002F\u002F ❌ Sai\npublic class WrongCache {     \u002F\u002F Singleton\n    private readonly AppDbContext _ctx;       \u002F\u002F Scoped\n    public WrongCache(AppDbContext ctx) { _ctx = ctx; }\n    \u002F\u002F _ctx KHÔNG được dispose sau request đầu, dùng cho mọi request sau → bug!\n}\n",[514,1156,1157,1162,1167,1172,1177,1182],{"__ignoreMap":516},[555,1158,1159],{"class":557,"line":558},[555,1160,1161],{},"\u002F\u002F ❌ Sai\n",[555,1163,1164],{"class":557,"line":564},[555,1165,1166],{},"public class WrongCache {     \u002F\u002F Singleton\n",[555,1168,1169],{"class":557,"line":571},[555,1170,1171],{},"    private readonly AppDbContext _ctx;       \u002F\u002F Scoped\n",[555,1173,1174],{"class":557,"line":577},[555,1175,1176],{},"    public WrongCache(AppDbContext ctx) { _ctx = ctx; }\n",[555,1178,1179],{"class":557,"line":583},[555,1180,1181],{},"    \u002F\u002F _ctx KHÔNG được dispose sau request đầu, dùng cho mọi request sau → bug!\n",[555,1183,1184],{"class":557,"line":589},[555,1185,674],{},[431,1187,1188,1145,1191,1194],{},[442,1189,1190],{},"Fix:",[514,1192,1193],{},"IServiceScopeFactory"," thay vì DbContext trực tiếp:",[507,1196,1198],{"className":549,"code":1197,"language":551,"meta":516,"style":516},"public class CorrectCache {\n    private readonly IServiceScopeFactory _scopeFactory;\n    public CorrectCache(IServiceScopeFactory f) => _scopeFactory = f;\n    \n    public void Refresh() {\n        using var scope = _scopeFactory.CreateScope();\n        var ctx = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n        \u002F\u002F dùng ctx trong scope này, dispose cuối using\n    }\n}\n",[514,1199,1200,1205,1210,1215,1219,1224,1229,1234,1239,1243],{"__ignoreMap":516},[555,1201,1202],{"class":557,"line":558},[555,1203,1204],{},"public class CorrectCache {\n",[555,1206,1207],{"class":557,"line":564},[555,1208,1209],{},"    private readonly IServiceScopeFactory _scopeFactory;\n",[555,1211,1212],{"class":557,"line":571},[555,1213,1214],{},"    public CorrectCache(IServiceScopeFactory f) => _scopeFactory = f;\n",[555,1216,1217],{"class":557,"line":577},[555,1218,762],{},[555,1220,1221],{"class":557,"line":583},[555,1222,1223],{},"    public void Refresh() {\n",[555,1225,1226],{"class":557,"line":589},[555,1227,1228],{},"        using var scope = _scopeFactory.CreateScope();\n",[555,1230,1231],{"class":557,"line":595},[555,1232,1233],{},"        var ctx = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n",[555,1235,1236],{"class":557,"line":601},[555,1237,1238],{},"        \u002F\u002F dùng ctx trong scope này, dispose cuối using\n",[555,1240,1241],{"class":557,"line":607},[555,1242,792],{},[555,1244,1245],{"class":557,"line":613},[555,1246,674],{},[502,1248,1250],{"id":1249},"_24-constructor-injection-chuẩn","2.4. Constructor injection chuẩn",[507,1252,1254],{"className":549,"code":1253,"language":551,"meta":516,"style":516},"public class OrderService {\n    private readonly IOrderRepository _repo;\n    private readonly INotificationService _notifier;\n    private readonly ILogger\u003COrderService> _logger;\n    \n    public OrderService(\n        IOrderRepository repo,\n        INotificationService notifier,\n        ILogger\u003COrderService> logger) {\n        _repo = repo;\n        _notifier = notifier;\n        _logger = logger;\n    }\n}\n",[514,1255,1256,1261,1266,1271,1276,1280,1285,1290,1295,1300,1305,1310,1314,1318],{"__ignoreMap":516},[555,1257,1258],{"class":557,"line":558},[555,1259,1260],{},"public class OrderService {\n",[555,1262,1263],{"class":557,"line":564},[555,1264,1265],{},"    private readonly IOrderRepository _repo;\n",[555,1267,1268],{"class":557,"line":571},[555,1269,1270],{},"    private readonly INotificationService _notifier;\n",[555,1272,1273],{"class":557,"line":577},[555,1274,1275],{},"    private readonly ILogger\u003COrderService> _logger;\n",[555,1277,1278],{"class":557,"line":583},[555,1279,762],{},[555,1281,1282],{"class":557,"line":589},[555,1283,1284],{},"    public OrderService(\n",[555,1286,1287],{"class":557,"line":595},[555,1288,1289],{},"        IOrderRepository repo,\n",[555,1291,1292],{"class":557,"line":601},[555,1293,1294],{},"        INotificationService notifier,\n",[555,1296,1297],{"class":557,"line":607},[555,1298,1299],{},"        ILogger\u003COrderService> logger) {\n",[555,1301,1302],{"class":557,"line":613},[555,1303,1304],{},"        _repo = repo;\n",[555,1306,1307],{"class":557,"line":619},[555,1308,1309],{},"        _notifier = notifier;\n",[555,1311,1312],{"class":557,"line":625},[555,1313,787],{},[555,1315,1316],{"class":557,"line":631},[555,1317,792],{},[555,1319,1320],{"class":557,"line":636},[555,1321,674],{},[431,1323,1324,1325,1328],{},"→ Dependency rõ ràng, immutable (",[514,1326,1327],{},"readonly","), test dễ (mock interface).",[502,1330,1332],{"id":1331},"_25-đăng-ký-nhiều-implementation","2.5. Đăng ký nhiều implementation",[507,1334,1336],{"className":549,"code":1335,"language":551,"meta":516,"style":516},"services.AddScoped\u003CINotifier, EmailNotifier>();\nservices.AddScoped\u003CINotifier, SmsNotifier>();\n\n\u002F\u002F Inject IEnumerable\u003CINotifier> → nhận hết\npublic class AlertService {\n    private readonly IEnumerable\u003CINotifier> _notifiers;\n    public AlertService(IEnumerable\u003CINotifier> notifiers) => _notifiers = notifiers;\n    \n    public async Task BroadcastAsync(string msg) {\n        foreach (var n in _notifiers) await n.SendAsync(msg);\n    }\n}\n",[514,1337,1338,1343,1348,1352,1357,1362,1367,1372,1376,1381,1386,1390],{"__ignoreMap":516},[555,1339,1340],{"class":557,"line":558},[555,1341,1342],{},"services.AddScoped\u003CINotifier, EmailNotifier>();\n",[555,1344,1345],{"class":557,"line":564},[555,1346,1347],{},"services.AddScoped\u003CINotifier, SmsNotifier>();\n",[555,1349,1350],{"class":557,"line":571},[555,1351,568],{"emptyLinePlaceholder":567},[555,1353,1354],{"class":557,"line":577},[555,1355,1356],{},"\u002F\u002F Inject IEnumerable\u003CINotifier> → nhận hết\n",[555,1358,1359],{"class":557,"line":583},[555,1360,1361],{},"public class AlertService {\n",[555,1363,1364],{"class":557,"line":589},[555,1365,1366],{},"    private readonly IEnumerable\u003CINotifier> _notifiers;\n",[555,1368,1369],{"class":557,"line":595},[555,1370,1371],{},"    public AlertService(IEnumerable\u003CINotifier> notifiers) => _notifiers = notifiers;\n",[555,1373,1374],{"class":557,"line":601},[555,1375,762],{},[555,1377,1378],{"class":557,"line":607},[555,1379,1380],{},"    public async Task BroadcastAsync(string msg) {\n",[555,1382,1383],{"class":557,"line":613},[555,1384,1385],{},"        foreach (var n in _notifiers) await n.SendAsync(msg);\n",[555,1387,1388],{"class":557,"line":619},[555,1389,792],{},[555,1391,1392],{"class":557,"line":625},[555,1393,674],{},[495,1395],{},[426,1397,1399],{"id":1398},"_3-rest-api-design","3. REST API design",[502,1401,1403],{"id":1402},"_31-http-methods-idempotency","3.1. HTTP Methods + Idempotency",[952,1405,1406,1425],{},[955,1407,1408],{},[958,1409,1410,1413,1416,1419,1422],{},[961,1411,1412],{},"Method",[961,1414,1415],{},"Mục đích",[961,1417,1418],{},"Safe?",[961,1420,1421],{},"Idempotent?",[961,1423,1424],{},"Status thường",[967,1426,1427,1443,1459,1474,1490],{},[958,1428,1429,1432,1435,1438,1440],{},[972,1430,1431],{},"GET",[972,1433,1434],{},"Đọc",[972,1436,1437],{},"✅",[972,1439,1437],{},[972,1441,1442],{},"200, 404",[958,1444,1445,1448,1451,1454,1456],{},[972,1446,1447],{},"POST",[972,1449,1450],{},"Tạo mới",[972,1452,1453],{},"❌",[972,1455,1453],{},[972,1457,1458],{},"201, 400",[958,1460,1461,1464,1467,1469,1471],{},[972,1462,1463],{},"PUT",[972,1465,1466],{},"Thay thế toàn bộ",[972,1468,1453],{},[972,1470,1437],{},[972,1472,1473],{},"200, 204, 404",[958,1475,1476,1479,1482,1484,1487],{},[972,1477,1478],{},"PATCH",[972,1480,1481],{},"Cập nhật một phần",[972,1483,1453],{},[972,1485,1486],{},"(thường ✅)",[972,1488,1489],{},"200, 204",[958,1491,1492,1495,1498,1500,1502],{},[972,1493,1494],{},"DELETE",[972,1496,1497],{},"Xoá",[972,1499,1453],{},[972,1501,1437],{},[972,1503,1504],{},"204, 404",[489,1506,1507,1508,1511,1512,1515,1516,1519],{"color":491,"icon":492},"🟢 ",[442,1509,1510],{},"Idempotent"," = gọi nhiều lần kết quả ",[442,1513,1514],{},"như gọi 1 lần",". ",[442,1517,1518],{},"Safe"," = không thay đổi dữ liệu (read-only).",[502,1521,1523],{"id":1522},"_32-vì-sao-put-idempotent-mà-post-không","3.2. 🟡 Vì sao PUT idempotent mà POST không?",[507,1525,1528],{"className":1526,"code":1527,"language":512},[510],"PUT \u002Fusers\u002F123 { name: \"Alice\" }\n→ user 123 có name = \"Alice\"\nGọi lại lần 2: vẫn user 123 có name = \"Alice\" → cùng kết quả ✅\n\nPOST \u002Fusers { name: \"Alice\" }\n→ tạo user 124 có name = \"Alice\"\nGọi lại: tạo user 125 → khác kết quả ❌\n",[514,1529,1527],{"__ignoreMap":516},[502,1531,1533],{"id":1532},"_33-status-code-phải-thuộc","3.3. Status code phải thuộc",[952,1535,1536,1549],{},[955,1537,1538],{},[958,1539,1540,1543,1546],{},[961,1541,1542],{},"Code",[961,1544,1545],{},"Khi nào",[961,1547,1548],{},"Ví dụ",[967,1550,1551,1565,1583,1597,1611,1624,1638,1652,1666,1680],{},[958,1552,1553,1559,1562],{},[972,1554,1555,1558],{},[442,1556,1557],{},"200"," OK",[972,1560,1561],{},"GET, PUT có body",[972,1563,1564],{},"Trả user info",[958,1566,1567,1573,1576],{},[972,1568,1569,1572],{},[442,1570,1571],{},"201"," Created",[972,1574,1575],{},"POST tạo xong",[972,1577,1578,1579,1582],{},"Trả 201 + ",[514,1580,1581],{},"Location"," header trỏ tới resource mới",[958,1584,1585,1591,1594],{},[972,1586,1587,1590],{},[442,1588,1589],{},"204"," No Content",[972,1592,1593],{},"DELETE, PUT thành công không body",[972,1595,1596],{},"–",[958,1598,1599,1605,1608],{},[972,1600,1601,1604],{},[442,1602,1603],{},"400"," Bad Request",[972,1606,1607],{},"Client gửi data sai format",[972,1609,1610],{},"Validation fail",[958,1612,1613,1619,1622],{},[972,1614,1615,1618],{},[442,1616,1617],{},"401"," Unauthorized",[972,1620,1621],{},"Chưa login \u002F sai token",[972,1623,1596],{},[958,1625,1626,1632,1635],{},[972,1627,1628,1631],{},[442,1629,1630],{},"403"," Forbidden",[972,1633,1634],{},"Đã login nhưng không quyền",[972,1636,1637],{},"User thường gọi endpoint admin",[958,1639,1640,1646,1649],{},[972,1641,1642,1645],{},[442,1643,1644],{},"404"," Not Found",[972,1647,1648],{},"Resource không tồn tại",[972,1650,1651],{},"GET \u002Fusers\u002F9999",[958,1653,1654,1660,1663],{},[972,1655,1656,1659],{},[442,1657,1658],{},"409"," Conflict",[972,1661,1662],{},"Mâu thuẫn dữ liệu",[972,1664,1665],{},"Duplicate email khi register",[958,1667,1668,1674,1677],{},[972,1669,1670,1673],{},[442,1671,1672],{},"422"," Unprocessable",[972,1675,1676],{},"Data hợp lệ syntax, vi phạm business rule",[972,1678,1679],{},"Số dư không đủ",[958,1681,1682,1688,1691],{},[972,1683,1684,1687],{},[442,1685,1686],{},"500"," Server Error",[972,1689,1690],{},"Lỗi unhandled",[972,1692,1693],{},"Đừng nuốt exception trả 200!",[502,1695,1697],{"id":1696},"_34-controller-chuẩn","3.4. Controller chuẩn",[507,1699,1701],{"className":549,"code":1700,"language":551,"meta":516,"style":516},"[ApiController]\n[Route(\"api\u002F[controller]\")]\npublic class UsersController : ControllerBase {\n    private readonly IUserService _service;\n    public UsersController(IUserService service) => _service = service;\n    \n    [HttpGet]\n    public async Task\u003CActionResult\u003CIEnumerable\u003CUserDto>>> GetAll() =>\n        Ok(await _service.GetAllAsync());\n    \n    [HttpGet(\"{id:int}\")]\n    public async Task\u003CActionResult\u003CUserDto>> Get(int id) {\n        var u = await _service.GetByIdAsync(id);\n        return u is null ? NotFound() : Ok(u);\n    }\n    \n    [HttpPost]\n    public async Task\u003CActionResult\u003CUserDto>> Create(CreateUserDto dto) {\n        var created = await _service.CreateAsync(dto);\n        return CreatedAtAction(nameof(Get), new { id = created.Id }, created);\n        \u002F\u002F ↑ Trả 201 + Location header + body\n    }\n    \n    [HttpPut(\"{id:int}\")]\n    public async Task\u003CIActionResult> Update(int id, UpdateUserDto dto) {\n        await _service.UpdateAsync(id, dto);\n        return NoContent();    \u002F\u002F 204\n    }\n    \n    [HttpDelete(\"{id:int}\")]\n    public async Task\u003CIActionResult> Delete(int id) {\n        await _service.DeleteAsync(id);\n        return NoContent();\n    }\n}\n",[514,1702,1703,1708,1713,1718,1723,1728,1732,1737,1742,1747,1751,1756,1761,1766,1771,1775,1779,1784,1789,1794,1799,1804,1808,1812,1817,1822,1827,1832,1836,1840,1845,1850,1856,1862,1867],{"__ignoreMap":516},[555,1704,1705],{"class":557,"line":558},[555,1706,1707],{},"[ApiController]\n",[555,1709,1710],{"class":557,"line":564},[555,1711,1712],{},"[Route(\"api\u002F[controller]\")]\n",[555,1714,1715],{"class":557,"line":571},[555,1716,1717],{},"public class UsersController : ControllerBase {\n",[555,1719,1720],{"class":557,"line":577},[555,1721,1722],{},"    private readonly IUserService _service;\n",[555,1724,1725],{"class":557,"line":583},[555,1726,1727],{},"    public UsersController(IUserService service) => _service = service;\n",[555,1729,1730],{"class":557,"line":589},[555,1731,762],{},[555,1733,1734],{"class":557,"line":595},[555,1735,1736],{},"    [HttpGet]\n",[555,1738,1739],{"class":557,"line":601},[555,1740,1741],{},"    public async Task\u003CActionResult\u003CIEnumerable\u003CUserDto>>> GetAll() =>\n",[555,1743,1744],{"class":557,"line":607},[555,1745,1746],{},"        Ok(await _service.GetAllAsync());\n",[555,1748,1749],{"class":557,"line":613},[555,1750,762],{},[555,1752,1753],{"class":557,"line":619},[555,1754,1755],{},"    [HttpGet(\"{id:int}\")]\n",[555,1757,1758],{"class":557,"line":625},[555,1759,1760],{},"    public async Task\u003CActionResult\u003CUserDto>> Get(int id) {\n",[555,1762,1763],{"class":557,"line":631},[555,1764,1765],{},"        var u = await _service.GetByIdAsync(id);\n",[555,1767,1768],{"class":557,"line":636},[555,1769,1770],{},"        return u is null ? NotFound() : Ok(u);\n",[555,1772,1773],{"class":557,"line":642},[555,1774,792],{},[555,1776,1777],{"class":557,"line":647},[555,1778,762],{},[555,1780,1781],{"class":557,"line":653},[555,1782,1783],{},"    [HttpPost]\n",[555,1785,1786],{"class":557,"line":659},[555,1787,1788],{},"    public async Task\u003CActionResult\u003CUserDto>> Create(CreateUserDto dto) {\n",[555,1790,1791],{"class":557,"line":665},[555,1792,1793],{},"        var created = await _service.CreateAsync(dto);\n",[555,1795,1796],{"class":557,"line":671},[555,1797,1798],{},"        return CreatedAtAction(nameof(Get), new { id = created.Id }, created);\n",[555,1800,1801],{"class":557,"line":677},[555,1802,1803],{},"        \u002F\u002F ↑ Trả 201 + Location header + body\n",[555,1805,1806],{"class":557,"line":683},[555,1807,792],{},[555,1809,1810],{"class":557,"line":689},[555,1811,762],{},[555,1813,1814],{"class":557,"line":695},[555,1815,1816],{},"    [HttpPut(\"{id:int}\")]\n",[555,1818,1819],{"class":557,"line":701},[555,1820,1821],{},"    public async Task\u003CIActionResult> Update(int id, UpdateUserDto dto) {\n",[555,1823,1824],{"class":557,"line":707},[555,1825,1826],{},"        await _service.UpdateAsync(id, dto);\n",[555,1828,1829],{"class":557,"line":713},[555,1830,1831],{},"        return NoContent();    \u002F\u002F 204\n",[555,1833,1834],{"class":557,"line":719},[555,1835,792],{},[555,1837,1838],{"class":557,"line":725},[555,1839,762],{},[555,1841,1842],{"class":557,"line":730},[555,1843,1844],{},"    [HttpDelete(\"{id:int}\")]\n",[555,1846,1847],{"class":557,"line":889},[555,1848,1849],{},"    public async Task\u003CIActionResult> Delete(int id) {\n",[555,1851,1853],{"class":557,"line":1852},32,[555,1854,1855],{},"        await _service.DeleteAsync(id);\n",[555,1857,1859],{"class":557,"line":1858},33,[555,1860,1861],{},"        return NoContent();\n",[555,1863,1865],{"class":557,"line":1864},34,[555,1866,792],{},[555,1868,1870],{"class":557,"line":1869},35,[555,1871,674],{},[502,1873,1875,1876,1879],{"id":1874},"_35-apicontroller-magic","3.5. ",[514,1877,1878],{},"[ApiController]"," magic",[507,1881,1883],{"className":549,"code":1882,"language":551,"meta":516,"style":516},"[ApiController]\npublic class UsersController : ControllerBase { ... }\n",[514,1884,1885,1889],{"__ignoreMap":516},[555,1886,1887],{"class":557,"line":558},[555,1888,1707],{},[555,1890,1891],{"class":557,"line":564},[555,1892,1893],{},"public class UsersController : ControllerBase { ... }\n",[431,1895,1896,1898],{},[514,1897,1878],{}," tự động:",[435,1900,1901,1911,1917,1923],{},[438,1902,1903,1906,1907,1910],{},[442,1904,1905],{},"Validation"," — nếu DTO có ",[514,1908,1909],{},"[Required]"," không pass → tự trả 400 ProblemDetails.",[438,1912,1913,1916],{},[442,1914,1915],{},"Model binding"," — bind body\u002Froute\u002Fquery thông minh.",[438,1918,1919,1922],{},[442,1920,1921],{},"Attribute routing"," required.",[438,1924,1925,1928],{},[442,1926,1927],{},"ProblemDetails"," cho error response (chuẩn RFC 7807).",[495,1930],{},[426,1932,1934],{"id":1933},"_4-jwt-authentication","4. JWT Authentication",[502,1936,1938],{"id":1937},"_41-jwt-cấu-trúc","4.1. JWT cấu trúc",[507,1940,1943],{"className":1941,"code":1942,"language":512},[510],"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmFtZSI6IkFsaWNlIn0.signature\n└────── header ──────┘.└────── payload ──────┘.└─── signature ───┘\n",[514,1944,1942],{"__ignoreMap":516},[431,1946,1947,1948,1086],{},"3 phần base64url-encoded, phân tách bởi ",[514,1949,456],{},[435,1951,1952,1961,1969],{},[438,1953,1954,1957,1958,456],{},[442,1955,1956],{},"Header",": ",[514,1959,1960],{},"{ \"alg\": \"HS256\", \"typ\": \"JWT\" }",[438,1962,1963,1957,1966,456],{},[442,1964,1965],{},"Payload (claims)",[514,1967,1968],{},"{ \"sub\": \"1\", \"name\": \"Alice\", \"exp\": 1700000000 }",[438,1970,1971,1974],{},[442,1972,1973],{},"Signature",": HMAC\u002FRSA của (header + \".\" + payload + secret).",[502,1976,1978],{"id":1977},"_42-setup-aspnet-core","4.2. Setup ASP.NET Core",[507,1980,1982],{"className":549,"code":1981,"language":551,"meta":516,"style":516},"\u002F\u002F Program.cs\nbuilder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n    .AddJwtBearer(opt => {\n        opt.TokenValidationParameters = new TokenValidationParameters {\n            ValidateIssuer = true,\n            ValidateAudience = true,\n            ValidateLifetime = true,\n            ValidateIssuerSigningKey = true,\n            ValidIssuer = builder.Configuration[\"Jwt:Issuer\"],\n            ValidAudience = builder.Configuration[\"Jwt:Audience\"],\n            IssuerSigningKey = new SymmetricSecurityKey(\n                Encoding.UTF8.GetBytes(builder.Configuration[\"Jwt:Key\"]!))\n        };\n    });\nbuilder.Services.AddAuthorization();\n\n\u002F\u002F ...\napp.UseAuthentication();   \u002F\u002F PHẢI trước Authorization\napp.UseAuthorization();\n",[514,1983,1984,1989,1993,1998,2003,2008,2013,2018,2023,2028,2033,2038,2043,2048,2053,2057,2061,2066,2071],{"__ignoreMap":516},[555,1985,1986],{"class":557,"line":558},[555,1987,1988],{},"\u002F\u002F Program.cs\n",[555,1990,1991],{"class":557,"line":564},[555,1992,604],{},[555,1994,1995],{"class":557,"line":571},[555,1996,1997],{},"    .AddJwtBearer(opt => {\n",[555,1999,2000],{"class":557,"line":577},[555,2001,2002],{},"        opt.TokenValidationParameters = new TokenValidationParameters {\n",[555,2004,2005],{"class":557,"line":583},[555,2006,2007],{},"            ValidateIssuer = true,\n",[555,2009,2010],{"class":557,"line":589},[555,2011,2012],{},"            ValidateAudience = true,\n",[555,2014,2015],{"class":557,"line":595},[555,2016,2017],{},"            ValidateLifetime = true,\n",[555,2019,2020],{"class":557,"line":601},[555,2021,2022],{},"            ValidateIssuerSigningKey = true,\n",[555,2024,2025],{"class":557,"line":607},[555,2026,2027],{},"            ValidIssuer = builder.Configuration[\"Jwt:Issuer\"],\n",[555,2029,2030],{"class":557,"line":613},[555,2031,2032],{},"            ValidAudience = builder.Configuration[\"Jwt:Audience\"],\n",[555,2034,2035],{"class":557,"line":619},[555,2036,2037],{},"            IssuerSigningKey = new SymmetricSecurityKey(\n",[555,2039,2040],{"class":557,"line":625},[555,2041,2042],{},"                Encoding.UTF8.GetBytes(builder.Configuration[\"Jwt:Key\"]!))\n",[555,2044,2045],{"class":557,"line":631},[555,2046,2047],{},"        };\n",[555,2049,2050],{"class":557,"line":636},[555,2051,2052],{},"    });\n",[555,2054,2055],{"class":557,"line":642},[555,2056,616],{},[555,2058,2059],{"class":557,"line":647},[555,2060,568],{"emptyLinePlaceholder":567},[555,2062,2063],{"class":557,"line":653},[555,2064,2065],{},"\u002F\u002F ...\n",[555,2067,2068],{"class":557,"line":659},[555,2069,2070],{},"app.UseAuthentication();   \u002F\u002F PHẢI trước Authorization\n",[555,2072,2073],{"class":557,"line":665},[555,2074,2075],{},"app.UseAuthorization();\n",[502,2077,2079],{"id":2078},"_43-sinh-token","4.3. Sinh token",[507,2081,2083],{"className":549,"code":2082,"language":551,"meta":516,"style":516},"public string GenerateToken(User user) {\n    var claims = new[] {\n        new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),\n        new Claim(ClaimTypes.Name, user.Email),\n        new Claim(ClaimTypes.Role, user.Role)\n    };\n    var key = new SymmetricSecurityKey(\n        Encoding.UTF8.GetBytes(_config[\"Jwt:Key\"]!));\n    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);\n    var token = new JwtSecurityToken(\n        issuer: _config[\"Jwt:Issuer\"],\n        audience: _config[\"Jwt:Audience\"],\n        claims: claims,\n        expires: DateTime.UtcNow.AddHours(1),\n        signingCredentials: creds);\n    return new JwtSecurityTokenHandler().WriteToken(token);\n}\n",[514,2084,2085,2090,2095,2100,2105,2110,2115,2120,2125,2130,2135,2140,2145,2150,2155,2160,2165],{"__ignoreMap":516},[555,2086,2087],{"class":557,"line":558},[555,2088,2089],{},"public string GenerateToken(User user) {\n",[555,2091,2092],{"class":557,"line":564},[555,2093,2094],{},"    var claims = new[] {\n",[555,2096,2097],{"class":557,"line":571},[555,2098,2099],{},"        new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),\n",[555,2101,2102],{"class":557,"line":577},[555,2103,2104],{},"        new Claim(ClaimTypes.Name, user.Email),\n",[555,2106,2107],{"class":557,"line":583},[555,2108,2109],{},"        new Claim(ClaimTypes.Role, user.Role)\n",[555,2111,2112],{"class":557,"line":589},[555,2113,2114],{},"    };\n",[555,2116,2117],{"class":557,"line":595},[555,2118,2119],{},"    var key = new SymmetricSecurityKey(\n",[555,2121,2122],{"class":557,"line":601},[555,2123,2124],{},"        Encoding.UTF8.GetBytes(_config[\"Jwt:Key\"]!));\n",[555,2126,2127],{"class":557,"line":607},[555,2128,2129],{},"    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);\n",[555,2131,2132],{"class":557,"line":613},[555,2133,2134],{},"    var token = new JwtSecurityToken(\n",[555,2136,2137],{"class":557,"line":619},[555,2138,2139],{},"        issuer: _config[\"Jwt:Issuer\"],\n",[555,2141,2142],{"class":557,"line":625},[555,2143,2144],{},"        audience: _config[\"Jwt:Audience\"],\n",[555,2146,2147],{"class":557,"line":631},[555,2148,2149],{},"        claims: claims,\n",[555,2151,2152],{"class":557,"line":636},[555,2153,2154],{},"        expires: DateTime.UtcNow.AddHours(1),\n",[555,2156,2157],{"class":557,"line":642},[555,2158,2159],{},"        signingCredentials: creds);\n",[555,2161,2162],{"class":557,"line":647},[555,2163,2164],{},"    return new JwtSecurityTokenHandler().WriteToken(token);\n",[555,2166,2167],{"class":557,"line":653},[555,2168,674],{},[502,2170,2172],{"id":2171},"_44-authentication-vs-authorization","4.4. 🟡 Authentication vs Authorization",[489,2174,2176,2181,2195],{"color":1071,"icon":2175},"i-lucide-star",[431,2177,903,2178],{},[442,2179,2180],{},"PV cốt lõi:",[435,2182,2183,2189],{},[438,2184,2185,2188],{},[442,2186,2187],{},"Authentication"," = \"Bạn là ai?\" — verify identity qua credentials \u002F token.",[438,2190,2191,2194],{},[442,2192,2193],{},"Authorization"," = \"Bạn được làm gì?\" — check role\u002Fpolicy\u002Fclaim.",[431,2196,2197,2198,2200,2201,2204,2205,2207,2208,2211],{},"Trong middleware: ",[514,2199,919],{}," populate ",[514,2202,2203],{},"HttpContext.User"," (ClaimsPrincipal). ",[514,2206,915],{}," check ",[514,2209,2210],{},"[Authorize(...)]"," dựa trên ClaimsPrincipal đó.",[495,2213],{},[426,2215,2217],{"id":2216},"_5-entity-framework-core","5. Entity Framework Core",[502,2219,2221],{"id":2220},"_51-dbcontext-unit-of-work-repository-facade","5.1. DbContext = Unit of Work + Repository facade",[507,2223,2225],{"className":549,"code":2224,"language":551,"meta":516,"style":516},"public class AppDbContext : DbContext {\n    public AppDbContext(DbContextOptions\u003CAppDbContext> opt) : base(opt) {}\n    \n    public DbSet\u003CUser> Users => Set\u003CUser>();\n    public DbSet\u003COrder> Orders => Set\u003COrder>();\n    \n    protected override void OnModelCreating(ModelBuilder mb) {\n        mb.Entity\u003CUser>(u => {\n            u.HasIndex(x => x.Email).IsUnique();\n            u.Property(x => x.Email).HasMaxLength(150).IsRequired();\n        });\n        \n        mb.Entity\u003COrder>()\n            .HasOne(o => o.User)\n            .WithMany(u => u.Orders)\n            .HasForeignKey(o => o.UserId);\n    }\n}\n",[514,2226,2227,2232,2237,2241,2246,2251,2255,2260,2265,2270,2275,2280,2284,2289,2294,2299,2304,2308],{"__ignoreMap":516},[555,2228,2229],{"class":557,"line":558},[555,2230,2231],{},"public class AppDbContext : DbContext {\n",[555,2233,2234],{"class":557,"line":564},[555,2235,2236],{},"    public AppDbContext(DbContextOptions\u003CAppDbContext> opt) : base(opt) {}\n",[555,2238,2239],{"class":557,"line":571},[555,2240,762],{},[555,2242,2243],{"class":557,"line":577},[555,2244,2245],{},"    public DbSet\u003CUser> Users => Set\u003CUser>();\n",[555,2247,2248],{"class":557,"line":583},[555,2249,2250],{},"    public DbSet\u003COrder> Orders => Set\u003COrder>();\n",[555,2252,2253],{"class":557,"line":589},[555,2254,762],{},[555,2256,2257],{"class":557,"line":595},[555,2258,2259],{},"    protected override void OnModelCreating(ModelBuilder mb) {\n",[555,2261,2262],{"class":557,"line":601},[555,2263,2264],{},"        mb.Entity\u003CUser>(u => {\n",[555,2266,2267],{"class":557,"line":607},[555,2268,2269],{},"            u.HasIndex(x => x.Email).IsUnique();\n",[555,2271,2272],{"class":557,"line":613},[555,2273,2274],{},"            u.Property(x => x.Email).HasMaxLength(150).IsRequired();\n",[555,2276,2277],{"class":557,"line":619},[555,2278,2279],{},"        });\n",[555,2281,2282],{"class":557,"line":625},[555,2283,811],{},[555,2285,2286],{"class":557,"line":631},[555,2287,2288],{},"        mb.Entity\u003COrder>()\n",[555,2290,2291],{"class":557,"line":636},[555,2292,2293],{},"            .HasOne(o => o.User)\n",[555,2295,2296],{"class":557,"line":642},[555,2297,2298],{},"            .WithMany(u => u.Orders)\n",[555,2300,2301],{"class":557,"line":647},[555,2302,2303],{},"            .HasForeignKey(o => o.UserId);\n",[555,2305,2306],{"class":557,"line":653},[555,2307,792],{},[555,2309,2310],{"class":557,"line":659},[555,2311,674],{},[502,2313,2315],{"id":2314},"_52-change-tracking-cơ-chế-bên-trong","5.2. 🟡 Change tracking — cơ chế bên trong",[489,2317,2318,2324,2356,2361],{"color":1071,"icon":268},[431,2319,2320,2321,1086],{},"🟡 EF Core tự theo dõi entity lấy ra qua DbContext. Mỗi entity có ",[442,2322,2323],{},"state",[435,2325,2326,2332,2338,2344,2350],{},[438,2327,2328,2331],{},[514,2329,2330],{},"Added",": chưa save, sẽ INSERT.",[438,2333,2334,2337],{},[514,2335,2336],{},"Modified",": load rồi sửa, sẽ UPDATE.",[438,2339,2340,2343],{},[514,2341,2342],{},"Unchanged",": load rồi không sửa, không có SQL.",[438,2345,2346,2349],{},[514,2347,2348],{},"Deleted",": gọi Remove, sẽ DELETE.",[438,2351,2352,2355],{},[514,2353,2354],{},"Detached",": không track.",[431,2357,2358,2359,1086],{},"Khi ",[514,2360,1096],{},[1105,2362,2363,2366,2369,2375],{},[438,2364,2365],{},"EF duyệt tracker, tìm entity Added\u002FModified\u002FDeleted.",[438,2367,2368],{},"Sinh SQL INSERT\u002FUPDATE\u002FDELETE.",[438,2370,2371,2372,456],{},"Wrap trong ",[442,2373,2374],{},"1 transaction",[438,2376,2377],{},"Execute, update state thành Unchanged.",[507,2379,2381],{"className":549,"code":2380,"language":551,"meta":516,"style":516},"\u002F\u002F Load và sửa\nvar user = await _db.Users.FindAsync(1);\nuser.Email = \"new@example.com\";\n\u002F\u002F state: Modified (auto track)\n\nawait _db.SaveChangesAsync();\n\u002F\u002F SQL: UPDATE Users SET Email = 'new@...' WHERE Id = 1\n",[514,2382,2383,2388,2393,2398,2403,2407,2412],{"__ignoreMap":516},[555,2384,2385],{"class":557,"line":558},[555,2386,2387],{},"\u002F\u002F Load và sửa\n",[555,2389,2390],{"class":557,"line":564},[555,2391,2392],{},"var user = await _db.Users.FindAsync(1);\n",[555,2394,2395],{"class":557,"line":571},[555,2396,2397],{},"user.Email = \"new@example.com\";\n",[555,2399,2400],{"class":557,"line":577},[555,2401,2402],{},"\u002F\u002F state: Modified (auto track)\n",[555,2404,2405],{"class":557,"line":583},[555,2406,568],{"emptyLinePlaceholder":567},[555,2408,2409],{"class":557,"line":589},[555,2410,2411],{},"await _db.SaveChangesAsync();\n",[555,2413,2414],{"class":557,"line":595},[555,2415,2416],{},"\u002F\u002F SQL: UPDATE Users SET Email = 'new@...' WHERE Id = 1\n",[502,2418,2420],{"id":2419},"_53-tracking-vs-asnotracking","5.3. Tracking vs AsNoTracking",[507,2422,2424],{"className":549,"code":2423,"language":551,"meta":516,"style":516},"\u002F\u002F Có tracking (default)\nvar users = await _db.Users.ToListAsync();\n\u002F\u002F EF lưu snapshot trong tracker → tốn RAM + CPU\n\n\u002F\u002F Không tracking — read-only, nhanh hơn 20–30%\nvar users = await _db.Users.AsNoTracking().ToListAsync();\n",[514,2425,2426,2431,2436,2441,2445,2450],{"__ignoreMap":516},[555,2427,2428],{"class":557,"line":558},[555,2429,2430],{},"\u002F\u002F Có tracking (default)\n",[555,2432,2433],{"class":557,"line":564},[555,2434,2435],{},"var users = await _db.Users.ToListAsync();\n",[555,2437,2438],{"class":557,"line":571},[555,2439,2440],{},"\u002F\u002F EF lưu snapshot trong tracker → tốn RAM + CPU\n",[555,2442,2443],{"class":557,"line":577},[555,2444,568],{"emptyLinePlaceholder":567},[555,2446,2447],{"class":557,"line":583},[555,2448,2449],{},"\u002F\u002F Không tracking — read-only, nhanh hơn 20–30%\n",[555,2451,2452],{"class":557,"line":589},[555,2453,2454],{},"var users = await _db.Users.AsNoTracking().ToListAsync();\n",[489,2456,2457,2458,2461,2462,2465],{"color":491,"icon":492},"🔵 ",[442,2459,2460],{},"Quy tắc:"," query chỉ đọc → ",[514,2463,2464],{},"AsNoTracking()",". Query cần update → tracking.",[502,2467,2469],{"id":2468},"_54-loading-strategies-4-cách","5.4. Loading strategies — 4 cách",[2471,2472,2474],"h4",{"id":2473},"_541-lazy-loading","5.4.1. Lazy Loading",[507,2476,2478],{"className":549,"code":2477,"language":551,"meta":516,"style":516},"\u002F\u002F Cần UseLazyLoadingProxies + virtual cho navigation property\npublic class User {\n    public int Id { get; set; }\n    public virtual ICollection\u003COrder> Orders { get; set; }   \u002F\u002F virtual\n}\n\nvar user = await _db.Users.FindAsync(1);\nvar orderCount = user.Orders.Count;   \u002F\u002F ← LÚC NÀY mới query lần 2\n",[514,2479,2480,2485,2490,2495,2500,2504,2508,2512],{"__ignoreMap":516},[555,2481,2482],{"class":557,"line":558},[555,2483,2484],{},"\u002F\u002F Cần UseLazyLoadingProxies + virtual cho navigation property\n",[555,2486,2487],{"class":557,"line":564},[555,2488,2489],{},"public class User {\n",[555,2491,2492],{"class":557,"line":571},[555,2493,2494],{},"    public int Id { get; set; }\n",[555,2496,2497],{"class":557,"line":577},[555,2498,2499],{},"    public virtual ICollection\u003COrder> Orders { get; set; }   \u002F\u002F virtual\n",[555,2501,2502],{"class":557,"line":583},[555,2503,674],{},[555,2505,2506],{"class":557,"line":589},[555,2507,568],{"emptyLinePlaceholder":567},[555,2509,2510],{"class":557,"line":595},[555,2511,2392],{},[555,2513,2514],{"class":557,"line":601},[555,2515,2516],{},"var orderCount = user.Orders.Count;   \u002F\u002F ← LÚC NÀY mới query lần 2\n",[431,2518,2519,2520,2523],{},"❌ ",[442,2521,2522],{},"Bẫy N+1",": loop 100 user → 1 query users + 100 query orders.",[2471,2525,2527],{"id":2526},"_542-eager-loading","5.4.2. Eager Loading",[507,2529,2531],{"className":549,"code":2530,"language":551,"meta":516,"style":516},"var users = await _db.Users\n    .Include(u => u.Orders)\n    .ThenInclude(o => o.OrderItems)\n    .ToListAsync();\n\u002F\u002F 1 query với JOIN (hoặc split query)\n",[514,2532,2533,2538,2543,2548,2553],{"__ignoreMap":516},[555,2534,2535],{"class":557,"line":558},[555,2536,2537],{},"var users = await _db.Users\n",[555,2539,2540],{"class":557,"line":564},[555,2541,2542],{},"    .Include(u => u.Orders)\n",[555,2544,2545],{"class":557,"line":571},[555,2546,2547],{},"    .ThenInclude(o => o.OrderItems)\n",[555,2549,2550],{"class":557,"line":577},[555,2551,2552],{},"    .ToListAsync();\n",[555,2554,2555],{"class":557,"line":583},[555,2556,2557],{},"\u002F\u002F 1 query với JOIN (hoặc split query)\n",[2471,2559,2561],{"id":2560},"_543-explicit-loading","5.4.3. Explicit Loading",[507,2563,2565],{"className":549,"code":2564,"language":551,"meta":516,"style":516},"var user = await _db.Users.FindAsync(1);\nawait _db.Entry(user).Collection(u => u.Orders).LoadAsync();\n\u002F\u002F Query thứ 2 chủ động khi cần\n",[514,2566,2567,2571,2576],{"__ignoreMap":516},[555,2568,2569],{"class":557,"line":558},[555,2570,2392],{},[555,2572,2573],{"class":557,"line":564},[555,2574,2575],{},"await _db.Entry(user).Collection(u => u.Orders).LoadAsync();\n",[555,2577,2578],{"class":557,"line":571},[555,2579,2580],{},"\u002F\u002F Query thứ 2 chủ động khi cần\n",[2471,2582,2584],{"id":2583},"_544-projection-tốt-nhất-cho-api","5.4.4. Projection (tốt nhất cho API)",[507,2586,2588],{"className":549,"code":2587,"language":551,"meta":516,"style":516},"var dtos = await _db.Users\n    .Select(u => new UserDto {\n        Id = u.Id,\n        Name = u.Name,\n        OrderCount = u.Orders.Count\n    })\n    .ToListAsync();\n\u002F\u002F SQL: SELECT u.Id, u.Name, (SELECT COUNT(*) FROM Orders WHERE UserId = u.Id) FROM Users\n\u002F\u002F → chỉ cột cần, không tracking, nhanh nhất\n",[514,2589,2590,2595,2600,2605,2610,2615,2620,2624,2629],{"__ignoreMap":516},[555,2591,2592],{"class":557,"line":558},[555,2593,2594],{},"var dtos = await _db.Users\n",[555,2596,2597],{"class":557,"line":564},[555,2598,2599],{},"    .Select(u => new UserDto {\n",[555,2601,2602],{"class":557,"line":571},[555,2603,2604],{},"        Id = u.Id,\n",[555,2606,2607],{"class":557,"line":577},[555,2608,2609],{},"        Name = u.Name,\n",[555,2611,2612],{"class":557,"line":583},[555,2613,2614],{},"        OrderCount = u.Orders.Count\n",[555,2616,2617],{"class":557,"line":589},[555,2618,2619],{},"    })\n",[555,2621,2622],{"class":557,"line":595},[555,2623,2552],{},[555,2625,2626],{"class":557,"line":601},[555,2627,2628],{},"\u002F\u002F SQL: SELECT u.Id, u.Name, (SELECT COUNT(*) FROM Orders WHERE UserId = u.Id) FROM Users\n",[555,2630,2631],{"class":557,"line":607},[555,2632,2633],{},"\u002F\u002F → chỉ cột cần, không tracking, nhanh nhất\n",[502,2635,2637],{"id":2636},"_55-demo-n1-problem","5.5. 🔴 Demo N+1 problem",[489,2639,2640,2648,2682,2687,2702,2707],{"color":1071,"icon":2175},[431,2641,903,2642,528,2645],{},[442,2643,2644],{},"PV cực hay:",[525,2646,2647],{},"\"N+1 là gì? Cho ví dụ + fix?\"",[507,2649,2651],{"className":549,"code":2650,"language":551,"meta":516,"style":516},"\u002F\u002F ❌ N+1 — 1 query users, N query orders\nvar users = _db.Users.ToList();        \u002F\u002F SELECT * FROM Users (1 query)\nforeach (var u in users) {\n    Console.WriteLine(u.Orders.Count); \u002F\u002F SELECT * FROM Orders WHERE UserId=? (N query)\n}\n\u002F\u002F → Total: 1 + N queries\n",[514,2652,2653,2658,2663,2668,2673,2677],{"__ignoreMap":516},[555,2654,2655],{"class":557,"line":558},[555,2656,2657],{},"\u002F\u002F ❌ N+1 — 1 query users, N query orders\n",[555,2659,2660],{"class":557,"line":564},[555,2661,2662],{},"var users = _db.Users.ToList();        \u002F\u002F SELECT * FROM Users (1 query)\n",[555,2664,2665],{"class":557,"line":571},[555,2666,2667],{},"foreach (var u in users) {\n",[555,2669,2670],{"class":557,"line":577},[555,2671,2672],{},"    Console.WriteLine(u.Orders.Count); \u002F\u002F SELECT * FROM Orders WHERE UserId=? (N query)\n",[555,2674,2675],{"class":557,"line":583},[555,2676,674],{},[555,2678,2679],{"class":557,"line":589},[555,2680,2681],{},"\u002F\u002F → Total: 1 + N queries\n",[431,2683,2684],{},[442,2685,2686],{},"Fix bằng Include:",[507,2688,2690],{"className":549,"code":2689,"language":551,"meta":516,"style":516},"var users = _db.Users.Include(u => u.Orders).ToList();\n\u002F\u002F 1 query JOIN\n",[514,2691,2692,2697],{"__ignoreMap":516},[555,2693,2694],{"class":557,"line":558},[555,2695,2696],{},"var users = _db.Users.Include(u => u.Orders).ToList();\n",[555,2698,2699],{"class":557,"line":564},[555,2700,2701],{},"\u002F\u002F 1 query JOIN\n",[431,2703,2704],{},[442,2705,2706],{},"Tốt hơn — Projection:",[507,2708,2710],{"className":549,"code":2709,"language":551,"meta":516,"style":516},"var data = _db.Users\n    .Select(u => new { u.Name, OrderCount = u.Orders.Count })\n    .ToList();\n\u002F\u002F 1 query, chỉ cột cần\n",[514,2711,2712,2717,2722,2727],{"__ignoreMap":516},[555,2713,2714],{"class":557,"line":558},[555,2715,2716],{},"var data = _db.Users\n",[555,2718,2719],{"class":557,"line":564},[555,2720,2721],{},"    .Select(u => new { u.Name, OrderCount = u.Orders.Count })\n",[555,2723,2724],{"class":557,"line":571},[555,2725,2726],{},"    .ToList();\n",[555,2728,2729],{"class":557,"line":577},[555,2730,2731],{},"\u002F\u002F 1 query, chỉ cột cần\n",[502,2733,2735],{"id":2734},"_56-migration-workflow","5.6. Migration workflow",[507,2737,2741],{"className":2738,"code":2739,"language":2740,"meta":516,"style":516},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Tạo migration mới\ndotnet ef migrations add InitialCreate\n\n# Apply lên DB\ndotnet ef database update\n\n# Sinh SQL script (production deploy)\ndotnet ef migrations script > init.sql\n\n# Rollback đến migration cụ thể\ndotnet ef database update PreviousMigrationName\n\n# Remove migration cuối (nếu chưa apply)\ndotnet ef migrations remove\n","bash",[514,2742,2743,2749,2768,2772,2777,2789,2793,2798,2816,2820,2825,2839,2843,2848],{"__ignoreMap":516},[555,2744,2745],{"class":557,"line":558},[555,2746,2748],{"class":2747},"sHwdD","# Tạo migration mới\n",[555,2750,2751,2755,2759,2762,2765],{"class":557,"line":564},[555,2752,2754],{"class":2753},"sBMFI","dotnet",[555,2756,2758],{"class":2757},"sfazB"," ef",[555,2760,2761],{"class":2757}," migrations",[555,2763,2764],{"class":2757}," add",[555,2766,2767],{"class":2757}," InitialCreate\n",[555,2769,2770],{"class":557,"line":571},[555,2771,568],{"emptyLinePlaceholder":567},[555,2773,2774],{"class":557,"line":577},[555,2775,2776],{"class":2747},"# Apply lên DB\n",[555,2778,2779,2781,2783,2786],{"class":557,"line":583},[555,2780,2754],{"class":2753},[555,2782,2758],{"class":2757},[555,2784,2785],{"class":2757}," database",[555,2787,2788],{"class":2757}," update\n",[555,2790,2791],{"class":557,"line":589},[555,2792,568],{"emptyLinePlaceholder":567},[555,2794,2795],{"class":557,"line":595},[555,2796,2797],{"class":2747},"# Sinh SQL script (production deploy)\n",[555,2799,2800,2802,2804,2806,2809,2813],{"class":557,"line":601},[555,2801,2754],{"class":2753},[555,2803,2758],{"class":2757},[555,2805,2761],{"class":2757},[555,2807,2808],{"class":2757}," script",[555,2810,2812],{"class":2811},"sMK4o"," >",[555,2814,2815],{"class":2757}," init.sql\n",[555,2817,2818],{"class":557,"line":607},[555,2819,568],{"emptyLinePlaceholder":567},[555,2821,2822],{"class":557,"line":613},[555,2823,2824],{"class":2747},"# Rollback đến migration cụ thể\n",[555,2826,2827,2829,2831,2833,2836],{"class":557,"line":619},[555,2828,2754],{"class":2753},[555,2830,2758],{"class":2757},[555,2832,2785],{"class":2757},[555,2834,2835],{"class":2757}," update",[555,2837,2838],{"class":2757}," PreviousMigrationName\n",[555,2840,2841],{"class":557,"line":625},[555,2842,568],{"emptyLinePlaceholder":567},[555,2844,2845],{"class":557,"line":631},[555,2846,2847],{"class":2747},"# Remove migration cuối (nếu chưa apply)\n",[555,2849,2850,2852,2854,2856],{"class":557,"line":636},[555,2851,2754],{"class":2753},[555,2853,2758],{"class":2757},[555,2855,2761],{"class":2757},[555,2857,2858],{"class":2757}," remove\n",[489,2860,2862,2867],{"color":1071,"icon":2861},"i-lucide-alert-triangle",[431,2863,1074,2864],{},[442,2865,2866],{},"Production deploy migration:",[1105,2868,2869,2876,2879,2882],{},[438,2870,2871,2872,2875],{},"Đừng ",[514,2873,2874],{},"dotnet ef database update"," trực tiếp production.",[438,2877,2878],{},"Sinh script SQL, review trước, deploy qua CI\u002FCD.",[438,2880,2881],{},"Test rollback trong staging.",[438,2883,2884],{},"Big migration (alter cột bảng triệu row) → batch \u002F online migration.",[502,2886,2888],{"id":2887},"_57-code-first-vs-database-first","5.7. Code-First vs Database-First",[952,2890,2891,2903],{},[955,2892,2893],{},[958,2894,2895,2897,2900],{},[961,2896],{},[961,2898,2899],{},"Code-First",[961,2901,2902],{},"Database-First",[967,2904,2905,2916,2927,2937],{},[958,2906,2907,2910,2913],{},[972,2908,2909],{},"Source of truth",[972,2911,2912],{},"C# class",[972,2914,2915],{},"Database schema",[958,2917,2918,2921,2924],{},[972,2919,2920],{},"Workflow",[972,2922,2923],{},"Code → migration → DB",[972,2925,2926],{},"DB → scaffold → C#",[958,2928,2929,2931,2934],{},[972,2930,1545],{},[972,2932,2933],{},"Greenfield, control schema",[972,2935,2936],{},"Legacy DB",[958,2938,2939,2942,2947],{},[972,2940,2941],{},"Lệnh",[972,2943,2944],{},[514,2945,2946],{},"dotnet ef migrations add",[972,2948,2949],{},[514,2950,2951],{},"dotnet ef dbcontext scaffold",[495,2953],{},[426,2955,2957],{"id":2956},"_6-câu-hỏi-tự-test-cuối-ngày","6. Câu hỏi tự test cuối ngày",[489,2959,2961,2966,2977,2998,3007],{"color":491,"icon":2960},"i-lucide-help-circle",[431,2962,2963],{},[442,2964,2965],{},"🟢 Intern:",[1105,2967,2968,2971,2974],{},[438,2969,2970],{},"Middleware là gì? Cho ví dụ 3 middleware có sẵn.",[438,2972,2973],{},"3 DI lifetime — kể tên + ý nghĩa.",[438,2975,2976],{},"Status code: 201, 204, 401, 403, 404 — mỗi cái khi nào dùng?",[431,2978,2979,2982,2983,2986,2987,2990,2991,484,2994,2997],{},[442,2980,2981],{},"🔵 Junior:","\n4. Vì sao ",[514,2984,2985],{},"UseAuthentication"," phải trước ",[514,2988,2989],{},"UseAuthorization","?\n5. DbContext đăng ký Scoped — vì sao?\n6. ",[514,2992,2993],{},"IActionResult",[514,2995,2996],{},"ActionResult\u003CT>"," khác gì?\n7. JWT có 3 phần — mỗi phần chứa gì?",[431,2999,3000,3003,3004,3006],{},[442,3001,3002],{},"🟡 Mid:","\n8. Captive dependency — là gì? Fix ra sao?\n9. EF Core change tracking — mô tả cơ chế.\n10. N+1 problem — demo + 3 cách fix.\n11. ",[514,3005,2464],{}," khi nào dùng, khi nào không?",[431,3008,3009,3012,3013,484,3016,3019],{},[442,3010,3011],{},"🔴 Senior:","\n12. Custom middleware vs Filter — khác gì? Khi nào dùng cái nào?\n13. EF Core ",[514,3014,3015],{},"Find()",[514,3017,3018],{},"FirstOrDefault()"," — khác cơ chế ra sao?\n14. Production migration cho bảng 100M row — quy trình?\n15. JWT vs Session — trade-off?",[431,3021,3022,528,3025,456],{},[442,3023,3024],{},"Đáp án:",[3026,3027,3028],"a",{"href":89},"Ngân hàng câu hỏi ASP.NET + EF",[495,3030],{},[431,3032,3033,3034],{},"➡️ Ngày mai: ",[3026,3035,57],{"href":58},[3037,3038,3039],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}",{"title":516,"searchDepth":564,"depth":564,"links":3041},[3042,3043,3052,3059,3067,3073,3082],{"id":428,"depth":564,"text":429},{"id":499,"depth":564,"text":500,"children":3044},[3045,3046,3048,3049,3050],{"id":504,"depth":571,"text":505},{"id":541,"depth":571,"text":3047},"1.2. Program.cs chuẩn .NET 8\u002F9",{"id":736,"depth":571,"text":737},{"id":895,"depth":571,"text":896},{"id":940,"depth":571,"text":3051},"1.5. Use vs Run vs Map",{"id":1020,"depth":564,"text":1021,"children":3053},[3054,3055,3056,3057,3058],{"id":1024,"depth":571,"text":1025},{"id":1067,"depth":571,"text":1068},{"id":1128,"depth":571,"text":1129},{"id":1249,"depth":571,"text":1250},{"id":1331,"depth":571,"text":1332},{"id":1398,"depth":564,"text":1399,"children":3060},[3061,3062,3063,3064,3065],{"id":1402,"depth":571,"text":1403},{"id":1522,"depth":571,"text":1523},{"id":1532,"depth":571,"text":1533},{"id":1696,"depth":571,"text":1697},{"id":1874,"depth":571,"text":3066},"3.5. [ApiController] magic",{"id":1933,"depth":564,"text":1934,"children":3068},[3069,3070,3071,3072],{"id":1937,"depth":571,"text":1938},{"id":1977,"depth":571,"text":1978},{"id":2078,"depth":571,"text":2079},{"id":2171,"depth":571,"text":2172},{"id":2216,"depth":564,"text":2217,"children":3074},[3075,3076,3077,3078,3079,3080,3081],{"id":2220,"depth":571,"text":2221},{"id":2314,"depth":571,"text":2315},{"id":2419,"depth":571,"text":2420},{"id":2468,"depth":571,"text":2469},{"id":2636,"depth":571,"text":2637},{"id":2734,"depth":571,"text":2735},{"id":2887,"depth":571,"text":2888},{"id":2956,"depth":564,"text":2957},"Middleware pipeline trace, DI lifetimes + captive dependency, EF Core change tracking internals, loading strategies với N+1 demo, migrations.","md",null,{},{"title":52,"icon":55},{"title":52,"description":3083},"J7kg9h8n-qgPpdL3qXcH9gvIXWlc2L_9hPor9heP94M",[3091,3093],{"title":47,"path":48,"stem":49,"description":3092,"icon":50,"children":-1},"B-tree INDEX internals, JOIN sâu, MVCC, ACID, isolation level mechanism, query plan. Mock data thật để test query.",{"title":57,"path":58,"stem":59,"description":3094,"icon":60,"children":-1},"Big O, array, string, linked list, stack, queue, hashmap. Học CÁCH SUY NGHĨ bài DSA — không chỉ code. Pattern chuẩn cho mọi bài.",1783490353821]