[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-microsoft-migrating-mvc-static-files":3,"mdc-a3gsed-key":35,"related-org-microsoft-migrating-mvc-static-files":1906,"related-repo-microsoft-migrating-mvc-static-files":2101},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":25,"repoUrl":26,"updatedAt":27,"license":28,"forks":29,"topics":30,"repo":31,"sourceUrl":33,"mdContent":34},"migrating-mvc-static-files","migrate MVC static files to Core","Migrates ASP.NET MVC static file serving and virtual path providers to ASP.NET Core conventions. Moves Content\u002F, Scripts\u002F, and App_Data\u002F folders into wwwroot\u002F, configures UseStaticFiles middleware, and replaces VirtualPathProvider with IFileProvider and EmbeddedFileProvider. Use when upgrading MVC apps that serve CSS from ~\u002FContent\u002F, JS from ~\u002FScripts\u002F, use VirtualPathProvider, serve embedded resources, or store files in App_Data. Also triggers for \"configure static files in Core\", \"wwwroot migration\", \"embedded resource serving\", or \"files outside wwwroot\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"microsoft","Microsoft","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fmicrosoft.png",[12,16,19,22],{"name":13,"slug":14,"type":15},"Backend","backend","tag",{"name":17,"slug":18,"type":15},".NET","net",{"name":20,"slug":21,"type":15},"ASP.NET Core","asp-net-core",{"name":23,"slug":24,"type":15},"Migration","migration",7,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fupgrade-agent-plugins","2026-07-03T16:30:56.988486",null,1,[],{"repoUrl":26,"stars":25,"forks":29,"topics":32,"description":28},[],"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fupgrade-agent-plugins\u002Ftree\u002FHEAD\u002Fplugins\u002Fupgrade-agent\u002Fextenders\u002Fupgrade-dotnet\u002Fupgrade\u002Fskills\u002Flazy\u002Fweb\u002Fmvc\u002Fmigrating-mvc-static-files","---\r\nname: migrating-mvc-static-files\r\ndescription: >\r\n  Migrates ASP.NET MVC static file serving and virtual path providers to ASP.NET Core conventions.\r\n  Moves Content\u002F, Scripts\u002F, and App_Data\u002F folders into wwwroot\u002F, configures UseStaticFiles middleware,\r\n  and replaces VirtualPathProvider with IFileProvider and EmbeddedFileProvider. Use when upgrading MVC\r\n  apps that serve CSS from ~\u002FContent\u002F, JS from ~\u002FScripts\u002F, use VirtualPathProvider, serve embedded\r\n  resources, or store files in App_Data. Also triggers for \"configure static files in Core\", \"wwwroot\r\n  migration\", \"embedded resource serving\", or \"files outside wwwroot\".\r\nmetadata:\r\n  traits: .NET|CSharp|VisualBasic|DotNetCore\r\n  discovery: lazy\r\n---\r\n\r\n# ASP.NET MVC Static Files and Asset Serving Migration\r\n\r\n## Overview\r\n\r\nASP.NET Framework serves any file from the project root automatically. ASP.NET Core does not — static files are only served from `wwwroot\u002F` by default, and the `UseStaticFiles` middleware must be explicitly registered. This skill migrates the folder layout, configures the middleware, and replaces `VirtualPathProvider` with `IFileProvider`.\r\n\r\n> **Related skill:** `migrating-mvc-bundling` handles bundle reference conversion. Complete bundling migration first so the files referenced by `\u003Cscript>`\u002F`\u003Clink>` tags are already in `wwwroot\u002F`.\r\n\r\n## Workflow\r\n\r\nTrack progress across these steps:\r\n\r\n```\r\nMigration Progress:\r\n- [ ] Step 1: Audit existing static file locations\r\n- [ ] Step 2: Create wwwroot structure and move files\r\n- [ ] Step 3: Register static file middleware\r\n- [ ] Step 4: Update path references in views and code\r\n- [ ] Step 5: Migrate VirtualPathProvider to IFileProvider\r\n- [ ] Step 6: Configure files outside wwwroot (if needed)\r\n- [ ] Step 7: Remove legacy folder references\r\n```\r\n\r\n### Step 1: Audit Existing Static File Locations\r\n\r\nSearch the project for static assets and note where they live:\r\n\r\n- `Content\u002F` — CSS files, images, fonts\r\n- `Scripts\u002F` — JavaScript files\r\n- `App_Data\u002F` — data files (not served in Core by default)\r\n- Files in the project root or other custom folders\r\n- Embedded resources referenced via `VirtualPathProvider`\r\n\r\nCheck `Web.config` for any `\u003CstaticContent>` MIME type mappings or custom `\u003Chandlers>` for static files. These will need equivalent configuration in Core.\r\n\r\n### Step 2: Create wwwroot Structure and Move Files\r\n\r\nCreate the `wwwroot\u002F` folder at the project root and move assets into it following ASP.NET Core conventions:\r\n\r\n**Before (ASP.NET MVC):**\r\n```\r\nMyApp\u002F\r\n├── Content\u002F\r\n│   ├── Site.css\r\n│   └── images\u002F\r\n│       └── logo.png\r\n├── Scripts\u002F\r\n│   ├── jquery-3.6.0.min.js\r\n│   └── site.js\r\n├── App_Data\u002F\r\n│   └── data.json\r\n├── fonts\u002F\r\n│   └── custom.woff2\r\n└── Web.config\r\n```\r\n\r\n**After (ASP.NET Core):**\r\n```\r\nMyApp\u002F\r\n├── wwwroot\u002F\r\n│   ├── css\u002F\r\n│   │   └── Site.css\r\n│   ├── js\u002F\r\n│   │   ├── jquery-3.6.0.min.js\r\n│   │   └── site.js\r\n│   ├── images\u002F\r\n│   │   └── logo.png\r\n│   ├── fonts\u002F\r\n│   │   └── custom.woff2\r\n│   └── data\u002F\r\n│       └── data.json    (only if public access needed)\r\n├── App_Data\u002F\r\n│   └── data.json        (keep here if private — read via file I\u002FO)\r\n└── Program.cs\r\n```\r\n\r\nKey decisions:\r\n- `Content\u002F` → `wwwroot\u002Fcss\u002F` (rename to match Core convention)\r\n- `Scripts\u002F` → `wwwroot\u002Fjs\u002F` (rename to match Core convention)\r\n- Images and fonts → `wwwroot\u002Fimages\u002F`, `wwwroot\u002Ffonts\u002F`\r\n- `App_Data\u002F` files that need web access → `wwwroot\u002Fdata\u002F`; files that should stay private → keep outside `wwwroot\u002F` and access via `IWebHostEnvironment.ContentRootPath`\r\n\r\nEnsure the project file includes `wwwroot\u002F` as web root content. SDK-style projects handle this automatically when the folder exists.\r\n\r\n### Step 3: Register Static File Middleware\r\n\r\nAdd `UseStaticFiles()` in `Program.cs`. Order matters — place it before routing middleware:\r\n\r\n**Before (ASP.NET MVC — implicit, no code needed):**\r\n```csharp\r\n\u002F\u002F Static files served automatically by IIS\u002FASP.NET pipeline\r\n```\r\n\r\n**After (ASP.NET Core):**\r\n```csharp\r\nvar app = builder.Build();\r\n\r\napp.UseStaticFiles(); \u002F\u002F Serves files from wwwroot\u002F\r\n\r\napp.UseRouting();\r\napp.UseAuthorization();\r\n\r\napp.MapControllerRoute(\r\n    name: \"default\",\r\n    pattern: \"{controller=Home}\u002F{action=Index}\u002F{id?}\");\r\n\r\napp.Run();\r\n```\r\n\r\nTo add custom MIME types (replacing `Web.config` `\u003CstaticContent>` entries):\r\n\r\n```csharp\r\nvar provider = new FileExtensionContentTypeProvider();\r\nprovider.Mappings[\".webmanifest\"] = \"application\u002Fmanifest+json\";\r\n\r\napp.UseStaticFiles(new StaticFileOptions\r\n{\r\n    ContentTypeProvider = provider\r\n});\r\n```\r\n\r\nTo configure cache headers for static files:\r\n\r\n```csharp\r\napp.UseStaticFiles(new StaticFileOptions\r\n{\r\n    OnPrepareResponse = ctx =>\r\n    {\r\n        ctx.Context.Response.Headers.Append(\"Cache-Control\", \"public,max-age=31536000\");\r\n    }\r\n});\r\n```\r\n\r\n### Step 4: Update Path References in Views and Code\r\n\r\nUpdate all references to the old folder paths in Razor views, CSS files, and C# code.\r\n\r\n**Razor views — `~\u002FContent\u002F` and `~\u002FScripts\u002F` references:**\r\n\r\nBefore:\r\n```cshtml\r\n\u003Clink href=\"~\u002FContent\u002FSite.css\" rel=\"stylesheet\" \u002F>\r\n\u003Cscript src=\"~\u002FScripts\u002Fsite.js\">\u003C\u002Fscript>\r\n\u003Cimg src=\"~\u002FContent\u002Fimages\u002Flogo.png\" alt=\"Logo\" \u002F>\r\n```\r\n\r\nAfter:\r\n```cshtml\r\n\u003Clink href=\"~\u002Fcss\u002FSite.css\" rel=\"stylesheet\" \u002F>\r\n\u003Cscript src=\"~\u002Fjs\u002Fsite.js\">\u003C\u002Fscript>\r\n\u003Cimg src=\"~\u002Fimages\u002Flogo.png\" alt=\"Logo\" \u002F>\r\n```\r\n\r\nThe `~\u002F` prefix continues to work in ASP.NET Core Razor views — it resolves to `wwwroot\u002F`.\r\n\r\n**CSS files — relative paths:**\r\n\r\nBefore:\r\n```css\r\nbackground-image: url('..\u002FContent\u002Fimages\u002Flogo.png');\r\n```\r\n\r\nAfter:\r\n```css\r\nbackground-image: url('..\u002Fimages\u002Flogo.png');\r\n```\r\n\r\n**C# code — `Server.MapPath` and `HostingEnvironment.MapPath`:**\r\n\r\nBefore:\r\n```csharp\r\nvar path = Server.MapPath(\"~\u002FApp_Data\u002Fdata.json\");\r\nvar path2 = HostingEnvironment.MapPath(\"~\u002FContent\u002Ftemplates\u002Freport.html\");\r\n```\r\n\r\nAfter:\r\n```csharp\r\n\u002F\u002F Inject IWebHostEnvironment via constructor\r\nvar path = Path.Combine(_env.ContentRootPath, \"App_Data\", \"data.json\");\r\nvar path2 = Path.Combine(_env.WebRootPath, \"templates\", \"report.html\");\r\n```\r\n\r\nUse `ContentRootPath` for private files outside `wwwroot\u002F` and `WebRootPath` for public files inside `wwwroot\u002F`.\r\n\r\n### Step 5: Migrate VirtualPathProvider to IFileProvider\r\n\r\nASP.NET MVC's `VirtualPathProvider` has no direct replacement. ASP.NET Core uses `IFileProvider` for the same purpose.\r\n\r\n**Embedded resource serving:**\r\n\r\nBefore (ASP.NET MVC):\r\n```csharp\r\n\u002F\u002F Custom VirtualPathProvider registered in Global.asax\r\nHostingEnvironment.RegisterVirtualPathProvider(new EmbeddedResourceProvider());\r\n```\r\n\r\nAfter (ASP.NET Core):\r\n```csharp\r\nvar embeddedProvider = new EmbeddedFileProvider(\r\n    typeof(Program).Assembly,\r\n    \"MyApp.EmbeddedAssets\");\r\n\r\napp.UseStaticFiles(new StaticFileOptions\r\n{\r\n    FileProvider = embeddedProvider,\r\n    RequestPath = \"\u002Fembedded\"\r\n});\r\n```\r\n\r\nMark resources as embedded in the project file:\r\n```xml\r\n\u003CItemGroup>\r\n  \u003CEmbeddedResource Include=\"EmbeddedAssets\u002F**\u002F*\" \u002F>\r\n\u003C\u002FItemGroup>\r\n```\r\n\r\n**Custom file system sources:**\r\n\r\nBefore (ASP.NET MVC):\r\n```csharp\r\npublic class DatabaseVirtualPathProvider : VirtualPathProvider\r\n{\r\n    public override bool FileExists(string virtualPath) { \u002F* ... *\u002F }\r\n    public override VirtualFile GetFile(string virtualPath) { \u002F* ... *\u002F }\r\n}\r\n```\r\n\r\nAfter (ASP.NET Core):\r\n```csharp\r\npublic class DatabaseFileProvider : IFileProvider\r\n{\r\n    public IFileInfo GetFileInfo(string subpath) { \u002F* ... *\u002F }\r\n    public IDirectoryContents GetDirectoryContents(string subpath) { \u002F* ... *\u002F }\r\n    public IChangeToken Watch(string filter) => NullChangeToken.Singleton;\r\n}\r\n```\r\n\r\nRegister the custom provider:\r\n```csharp\r\napp.UseStaticFiles(new StaticFileOptions\r\n{\r\n    FileProvider = new DatabaseFileProvider(connectionString),\r\n    RequestPath = \"\u002Fdynamic\"\r\n});\r\n```\r\n\r\nTo compose multiple providers (equivalent to chaining `VirtualPathProvider` instances):\r\n```csharp\r\nvar compositeProvider = new CompositeFileProvider(\r\n    builder.Environment.WebRootFileProvider,\r\n    new EmbeddedFileProvider(typeof(Program).Assembly),\r\n    new DatabaseFileProvider(connectionString));\r\n\r\napp.UseStaticFiles(new StaticFileOptions\r\n{\r\n    FileProvider = compositeProvider\r\n});\r\n```\r\n\r\n### Step 6: Configure Files Outside wwwroot\r\n\r\nFiles outside `wwwroot\u002F` are not served by default. To serve files from additional directories, add a second `UseStaticFiles` call with an explicit `PhysicalFileProvider`:\r\n\r\n```csharp\r\napp.UseStaticFiles(); \u002F\u002F Default: serves from wwwroot\u002F\r\n\r\napp.UseStaticFiles(new StaticFileOptions\r\n{\r\n    FileProvider = new PhysicalFileProvider(\r\n        Path.Combine(builder.Environment.ContentRootPath, \"StaticAssets\")),\r\n    RequestPath = \"\u002Fassets\"\r\n});\r\n```\r\n\r\nSkip this step if all public assets fit under `wwwroot\u002F`. Serving files from outside `wwwroot\u002F` adds complexity — prefer moving files into `wwwroot\u002F` when possible.\r\n\r\n### Step 7: Remove Legacy Folder References\r\n\r\nSearch the codebase for remaining references to the old folder structure and clean them up:\r\n\r\n- Remove `Content\u002F`, `Scripts\u002F` folders (now empty after move)\r\n- Remove `VirtualPathProvider` registration from `Global.asax` or startup\r\n- Remove `\u003CstaticContent>` entries from `Web.config` (if `Web.config` is being removed)\r\n- Remove `HostingEnvironment.MapPath` and `Server.MapPath` calls\r\n- Remove `HostingEnvironment.RegisterVirtualPathProvider` calls\r\n- Update any build scripts or CI pipelines that reference old paths\r\n\r\n## Success Criteria\r\n\r\n- `wwwroot\u002F` folder exists with `css\u002F`, `js\u002F`, `images\u002F` subfolders following Core conventions\r\n- `app.UseStaticFiles()` registered in `Program.cs` before routing middleware\r\n- All `~\u002FContent\u002F` and `~\u002FScripts\u002F` references updated to `~\u002Fcss\u002F` and `~\u002Fjs\u002F`\r\n- `Server.MapPath`\u002F`HostingEnvironment.MapPath` replaced with `IWebHostEnvironment` paths\r\n- `VirtualPathProvider` replaced with `IFileProvider`\u002F`EmbeddedFileProvider` (if applicable)\r\n- Custom MIME types from `Web.config` migrated to `FileExtensionContentTypeProvider`\r\n- No remaining references to `Content\u002F`, `Scripts\u002F`, or `VirtualPathProvider`\r\n- Project builds without errors\r\n",{"data":36,"body":40},{"name":4,"description":6,"metadata":37},{"traits":38,"discovery":39},".NET|CSharp|VisualBasic|DotNetCore","lazy",{"type":41,"children":42},"root",[43,52,59,98,143,149,154,166,173,178,231,260,266,278,286,295,303,312,317,404,416,422,443,451,469,476,587,605,667,672,732,738,743,767,772,805,810,841,860,868,872,906,910,937,960,964,987,991,1022,1055,1061,1080,1088,1092,1115,1119,1194,1199,1232,1240,1244,1290,1294,1347,1352,1396,1408,1483,1489,1515,1582,1608,1614,1619,1717,1723,1900],{"type":44,"tag":45,"props":46,"children":48},"element","h1",{"id":47},"aspnet-mvc-static-files-and-asset-serving-migration",[49],{"type":50,"value":51},"text","ASP.NET MVC Static Files and Asset Serving Migration",{"type":44,"tag":53,"props":54,"children":56},"h2",{"id":55},"overview",[57],{"type":50,"value":58},"Overview",{"type":44,"tag":60,"props":61,"children":62},"p",{},[63,65,72,74,80,82,88,90,96],{"type":50,"value":64},"ASP.NET Framework serves any file from the project root automatically. ASP.NET Core does not — static files are only served from ",{"type":44,"tag":66,"props":67,"children":69},"code",{"className":68},[],[70],{"type":50,"value":71},"wwwroot\u002F",{"type":50,"value":73}," by default, and the ",{"type":44,"tag":66,"props":75,"children":77},{"className":76},[],[78],{"type":50,"value":79},"UseStaticFiles",{"type":50,"value":81}," middleware must be explicitly registered. This skill migrates the folder layout, configures the middleware, and replaces ",{"type":44,"tag":66,"props":83,"children":85},{"className":84},[],[86],{"type":50,"value":87},"VirtualPathProvider",{"type":50,"value":89}," with ",{"type":44,"tag":66,"props":91,"children":93},{"className":92},[],[94],{"type":50,"value":95},"IFileProvider",{"type":50,"value":97},".",{"type":44,"tag":99,"props":100,"children":101},"blockquote",{},[102],{"type":44,"tag":60,"props":103,"children":104},{},[105,111,113,119,121,127,129,135,137,142],{"type":44,"tag":106,"props":107,"children":108},"strong",{},[109],{"type":50,"value":110},"Related skill:",{"type":50,"value":112}," ",{"type":44,"tag":66,"props":114,"children":116},{"className":115},[],[117],{"type":50,"value":118},"migrating-mvc-bundling",{"type":50,"value":120}," handles bundle reference conversion. Complete bundling migration first so the files referenced by ",{"type":44,"tag":66,"props":122,"children":124},{"className":123},[],[125],{"type":50,"value":126},"\u003Cscript>",{"type":50,"value":128},"\u002F",{"type":44,"tag":66,"props":130,"children":132},{"className":131},[],[133],{"type":50,"value":134},"\u003Clink>",{"type":50,"value":136}," tags are already in ",{"type":44,"tag":66,"props":138,"children":140},{"className":139},[],[141],{"type":50,"value":71},{"type":50,"value":97},{"type":44,"tag":53,"props":144,"children":146},{"id":145},"workflow",[147],{"type":50,"value":148},"Workflow",{"type":44,"tag":60,"props":150,"children":151},{},[152],{"type":50,"value":153},"Track progress across these steps:",{"type":44,"tag":155,"props":156,"children":160},"pre",{"className":157,"code":159,"language":50},[158],"language-text","Migration Progress:\n- [ ] Step 1: Audit existing static file locations\n- [ ] Step 2: Create wwwroot structure and move files\n- [ ] Step 3: Register static file middleware\n- [ ] Step 4: Update path references in views and code\n- [ ] Step 5: Migrate VirtualPathProvider to IFileProvider\n- [ ] Step 6: Configure files outside wwwroot (if needed)\n- [ ] Step 7: Remove legacy folder references\n",[161],{"type":44,"tag":66,"props":162,"children":164},{"__ignoreMap":163},"",[165],{"type":50,"value":159},{"type":44,"tag":167,"props":168,"children":170},"h3",{"id":169},"step-1-audit-existing-static-file-locations",[171],{"type":50,"value":172},"Step 1: Audit Existing Static File Locations",{"type":44,"tag":60,"props":174,"children":175},{},[176],{"type":50,"value":177},"Search the project for static assets and note where they live:",{"type":44,"tag":179,"props":180,"children":181},"ul",{},[182,194,205,216,221],{"type":44,"tag":183,"props":184,"children":185},"li",{},[186,192],{"type":44,"tag":66,"props":187,"children":189},{"className":188},[],[190],{"type":50,"value":191},"Content\u002F",{"type":50,"value":193}," — CSS files, images, fonts",{"type":44,"tag":183,"props":195,"children":196},{},[197,203],{"type":44,"tag":66,"props":198,"children":200},{"className":199},[],[201],{"type":50,"value":202},"Scripts\u002F",{"type":50,"value":204}," — JavaScript files",{"type":44,"tag":183,"props":206,"children":207},{},[208,214],{"type":44,"tag":66,"props":209,"children":211},{"className":210},[],[212],{"type":50,"value":213},"App_Data\u002F",{"type":50,"value":215}," — data files (not served in Core by default)",{"type":44,"tag":183,"props":217,"children":218},{},[219],{"type":50,"value":220},"Files in the project root or other custom folders",{"type":44,"tag":183,"props":222,"children":223},{},[224,226],{"type":50,"value":225},"Embedded resources referenced via ",{"type":44,"tag":66,"props":227,"children":229},{"className":228},[],[230],{"type":50,"value":87},{"type":44,"tag":60,"props":232,"children":233},{},[234,236,242,244,250,252,258],{"type":50,"value":235},"Check ",{"type":44,"tag":66,"props":237,"children":239},{"className":238},[],[240],{"type":50,"value":241},"Web.config",{"type":50,"value":243}," for any ",{"type":44,"tag":66,"props":245,"children":247},{"className":246},[],[248],{"type":50,"value":249},"\u003CstaticContent>",{"type":50,"value":251}," MIME type mappings or custom ",{"type":44,"tag":66,"props":253,"children":255},{"className":254},[],[256],{"type":50,"value":257},"\u003Chandlers>",{"type":50,"value":259}," for static files. These will need equivalent configuration in Core.",{"type":44,"tag":167,"props":261,"children":263},{"id":262},"step-2-create-wwwroot-structure-and-move-files",[264],{"type":50,"value":265},"Step 2: Create wwwroot Structure and Move Files",{"type":44,"tag":60,"props":267,"children":268},{},[269,271,276],{"type":50,"value":270},"Create the ",{"type":44,"tag":66,"props":272,"children":274},{"className":273},[],[275],{"type":50,"value":71},{"type":50,"value":277}," folder at the project root and move assets into it following ASP.NET Core conventions:",{"type":44,"tag":60,"props":279,"children":280},{},[281],{"type":44,"tag":106,"props":282,"children":283},{},[284],{"type":50,"value":285},"Before (ASP.NET MVC):",{"type":44,"tag":155,"props":287,"children":290},{"className":288,"code":289,"language":50},[158],"MyApp\u002F\n├── Content\u002F\n│   ├── Site.css\n│   └── images\u002F\n│       └── logo.png\n├── Scripts\u002F\n│   ├── jquery-3.6.0.min.js\n│   └── site.js\n├── App_Data\u002F\n│   └── data.json\n├── fonts\u002F\n│   └── custom.woff2\n└── Web.config\n",[291],{"type":44,"tag":66,"props":292,"children":293},{"__ignoreMap":163},[294],{"type":50,"value":289},{"type":44,"tag":60,"props":296,"children":297},{},[298],{"type":44,"tag":106,"props":299,"children":300},{},[301],{"type":50,"value":302},"After (ASP.NET Core):",{"type":44,"tag":155,"props":304,"children":307},{"className":305,"code":306,"language":50},[158],"MyApp\u002F\n├── wwwroot\u002F\n│   ├── css\u002F\n│   │   └── Site.css\n│   ├── js\u002F\n│   │   ├── jquery-3.6.0.min.js\n│   │   └── site.js\n│   ├── images\u002F\n│   │   └── logo.png\n│   ├── fonts\u002F\n│   │   └── custom.woff2\n│   └── data\u002F\n│       └── data.json    (only if public access needed)\n├── App_Data\u002F\n│   └── data.json        (keep here if private — read via file I\u002FO)\n└── Program.cs\n",[308],{"type":44,"tag":66,"props":309,"children":310},{"__ignoreMap":163},[311],{"type":50,"value":306},{"type":44,"tag":60,"props":313,"children":314},{},[315],{"type":50,"value":316},"Key decisions:",{"type":44,"tag":179,"props":318,"children":319},{},[320,338,354,373],{"type":44,"tag":183,"props":321,"children":322},{},[323,328,330,336],{"type":44,"tag":66,"props":324,"children":326},{"className":325},[],[327],{"type":50,"value":191},{"type":50,"value":329}," → ",{"type":44,"tag":66,"props":331,"children":333},{"className":332},[],[334],{"type":50,"value":335},"wwwroot\u002Fcss\u002F",{"type":50,"value":337}," (rename to match Core convention)",{"type":44,"tag":183,"props":339,"children":340},{},[341,346,347,353],{"type":44,"tag":66,"props":342,"children":344},{"className":343},[],[345],{"type":50,"value":202},{"type":50,"value":329},{"type":44,"tag":66,"props":348,"children":350},{"className":349},[],[351],{"type":50,"value":352},"wwwroot\u002Fjs\u002F",{"type":50,"value":337},{"type":44,"tag":183,"props":355,"children":356},{},[357,359,365,367],{"type":50,"value":358},"Images and fonts → ",{"type":44,"tag":66,"props":360,"children":362},{"className":361},[],[363],{"type":50,"value":364},"wwwroot\u002Fimages\u002F",{"type":50,"value":366},", ",{"type":44,"tag":66,"props":368,"children":370},{"className":369},[],[371],{"type":50,"value":372},"wwwroot\u002Ffonts\u002F",{"type":44,"tag":183,"props":374,"children":375},{},[376,381,383,389,391,396,398],{"type":44,"tag":66,"props":377,"children":379},{"className":378},[],[380],{"type":50,"value":213},{"type":50,"value":382}," files that need web access → ",{"type":44,"tag":66,"props":384,"children":386},{"className":385},[],[387],{"type":50,"value":388},"wwwroot\u002Fdata\u002F",{"type":50,"value":390},"; files that should stay private → keep outside ",{"type":44,"tag":66,"props":392,"children":394},{"className":393},[],[395],{"type":50,"value":71},{"type":50,"value":397}," and access via ",{"type":44,"tag":66,"props":399,"children":401},{"className":400},[],[402],{"type":50,"value":403},"IWebHostEnvironment.ContentRootPath",{"type":44,"tag":60,"props":405,"children":406},{},[407,409,414],{"type":50,"value":408},"Ensure the project file includes ",{"type":44,"tag":66,"props":410,"children":412},{"className":411},[],[413],{"type":50,"value":71},{"type":50,"value":415}," as web root content. SDK-style projects handle this automatically when the folder exists.",{"type":44,"tag":167,"props":417,"children":419},{"id":418},"step-3-register-static-file-middleware",[420],{"type":50,"value":421},"Step 3: Register Static File Middleware",{"type":44,"tag":60,"props":423,"children":424},{},[425,427,433,435,441],{"type":50,"value":426},"Add ",{"type":44,"tag":66,"props":428,"children":430},{"className":429},[],[431],{"type":50,"value":432},"UseStaticFiles()",{"type":50,"value":434}," in ",{"type":44,"tag":66,"props":436,"children":438},{"className":437},[],[439],{"type":50,"value":440},"Program.cs",{"type":50,"value":442},". Order matters — place it before routing middleware:",{"type":44,"tag":60,"props":444,"children":445},{},[446],{"type":44,"tag":106,"props":447,"children":448},{},[449],{"type":50,"value":450},"Before (ASP.NET MVC — implicit, no code needed):",{"type":44,"tag":155,"props":452,"children":456},{"className":453,"code":454,"language":455,"meta":163,"style":163},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F Static files served automatically by IIS\u002FASP.NET pipeline\n","csharp",[457],{"type":44,"tag":66,"props":458,"children":459},{"__ignoreMap":163},[460],{"type":44,"tag":461,"props":462,"children":464},"span",{"class":463,"line":29},"line",[465],{"type":44,"tag":461,"props":466,"children":467},{},[468],{"type":50,"value":454},{"type":44,"tag":60,"props":470,"children":471},{},[472],{"type":44,"tag":106,"props":473,"children":474},{},[475],{"type":50,"value":302},{"type":44,"tag":155,"props":477,"children":479},{"className":453,"code":478,"language":455,"meta":163,"style":163},"var app = builder.Build();\n\napp.UseStaticFiles(); \u002F\u002F Serves files from wwwroot\u002F\n\napp.UseRouting();\napp.UseAuthorization();\n\napp.MapControllerRoute(\n    name: \"default\",\n    pattern: \"{controller=Home}\u002F{action=Index}\u002F{id?}\");\n\napp.Run();\n",[480],{"type":44,"tag":66,"props":481,"children":482},{"__ignoreMap":163},[483,491,501,510,518,527,536,543,552,561,570,578],{"type":44,"tag":461,"props":484,"children":485},{"class":463,"line":29},[486],{"type":44,"tag":461,"props":487,"children":488},{},[489],{"type":50,"value":490},"var app = builder.Build();\n",{"type":44,"tag":461,"props":492,"children":494},{"class":463,"line":493},2,[495],{"type":44,"tag":461,"props":496,"children":498},{"emptyLinePlaceholder":497},true,[499],{"type":50,"value":500},"\n",{"type":44,"tag":461,"props":502,"children":504},{"class":463,"line":503},3,[505],{"type":44,"tag":461,"props":506,"children":507},{},[508],{"type":50,"value":509},"app.UseStaticFiles(); \u002F\u002F Serves files from wwwroot\u002F\n",{"type":44,"tag":461,"props":511,"children":513},{"class":463,"line":512},4,[514],{"type":44,"tag":461,"props":515,"children":516},{"emptyLinePlaceholder":497},[517],{"type":50,"value":500},{"type":44,"tag":461,"props":519,"children":521},{"class":463,"line":520},5,[522],{"type":44,"tag":461,"props":523,"children":524},{},[525],{"type":50,"value":526},"app.UseRouting();\n",{"type":44,"tag":461,"props":528,"children":530},{"class":463,"line":529},6,[531],{"type":44,"tag":461,"props":532,"children":533},{},[534],{"type":50,"value":535},"app.UseAuthorization();\n",{"type":44,"tag":461,"props":537,"children":538},{"class":463,"line":25},[539],{"type":44,"tag":461,"props":540,"children":541},{"emptyLinePlaceholder":497},[542],{"type":50,"value":500},{"type":44,"tag":461,"props":544,"children":546},{"class":463,"line":545},8,[547],{"type":44,"tag":461,"props":548,"children":549},{},[550],{"type":50,"value":551},"app.MapControllerRoute(\n",{"type":44,"tag":461,"props":553,"children":555},{"class":463,"line":554},9,[556],{"type":44,"tag":461,"props":557,"children":558},{},[559],{"type":50,"value":560},"    name: \"default\",\n",{"type":44,"tag":461,"props":562,"children":564},{"class":463,"line":563},10,[565],{"type":44,"tag":461,"props":566,"children":567},{},[568],{"type":50,"value":569},"    pattern: \"{controller=Home}\u002F{action=Index}\u002F{id?}\");\n",{"type":44,"tag":461,"props":571,"children":573},{"class":463,"line":572},11,[574],{"type":44,"tag":461,"props":575,"children":576},{"emptyLinePlaceholder":497},[577],{"type":50,"value":500},{"type":44,"tag":461,"props":579,"children":581},{"class":463,"line":580},12,[582],{"type":44,"tag":461,"props":583,"children":584},{},[585],{"type":50,"value":586},"app.Run();\n",{"type":44,"tag":60,"props":588,"children":589},{},[590,592,597,598,603],{"type":50,"value":591},"To add custom MIME types (replacing ",{"type":44,"tag":66,"props":593,"children":595},{"className":594},[],[596],{"type":50,"value":241},{"type":50,"value":112},{"type":44,"tag":66,"props":599,"children":601},{"className":600},[],[602],{"type":50,"value":249},{"type":50,"value":604}," entries):",{"type":44,"tag":155,"props":606,"children":608},{"className":453,"code":607,"language":455,"meta":163,"style":163},"var provider = new FileExtensionContentTypeProvider();\nprovider.Mappings[\".webmanifest\"] = \"application\u002Fmanifest+json\";\n\napp.UseStaticFiles(new StaticFileOptions\n{\n    ContentTypeProvider = provider\n});\n",[609],{"type":44,"tag":66,"props":610,"children":611},{"__ignoreMap":163},[612,620,628,635,643,651,659],{"type":44,"tag":461,"props":613,"children":614},{"class":463,"line":29},[615],{"type":44,"tag":461,"props":616,"children":617},{},[618],{"type":50,"value":619},"var provider = new FileExtensionContentTypeProvider();\n",{"type":44,"tag":461,"props":621,"children":622},{"class":463,"line":493},[623],{"type":44,"tag":461,"props":624,"children":625},{},[626],{"type":50,"value":627},"provider.Mappings[\".webmanifest\"] = \"application\u002Fmanifest+json\";\n",{"type":44,"tag":461,"props":629,"children":630},{"class":463,"line":503},[631],{"type":44,"tag":461,"props":632,"children":633},{"emptyLinePlaceholder":497},[634],{"type":50,"value":500},{"type":44,"tag":461,"props":636,"children":637},{"class":463,"line":512},[638],{"type":44,"tag":461,"props":639,"children":640},{},[641],{"type":50,"value":642},"app.UseStaticFiles(new StaticFileOptions\n",{"type":44,"tag":461,"props":644,"children":645},{"class":463,"line":520},[646],{"type":44,"tag":461,"props":647,"children":648},{},[649],{"type":50,"value":650},"{\n",{"type":44,"tag":461,"props":652,"children":653},{"class":463,"line":529},[654],{"type":44,"tag":461,"props":655,"children":656},{},[657],{"type":50,"value":658},"    ContentTypeProvider = provider\n",{"type":44,"tag":461,"props":660,"children":661},{"class":463,"line":25},[662],{"type":44,"tag":461,"props":663,"children":664},{},[665],{"type":50,"value":666},"});\n",{"type":44,"tag":60,"props":668,"children":669},{},[670],{"type":50,"value":671},"To configure cache headers for static files:",{"type":44,"tag":155,"props":673,"children":675},{"className":453,"code":674,"language":455,"meta":163,"style":163},"app.UseStaticFiles(new StaticFileOptions\n{\n    OnPrepareResponse = ctx =>\n    {\n        ctx.Context.Response.Headers.Append(\"Cache-Control\", \"public,max-age=31536000\");\n    }\n});\n",[676],{"type":44,"tag":66,"props":677,"children":678},{"__ignoreMap":163},[679,686,693,701,709,717,725],{"type":44,"tag":461,"props":680,"children":681},{"class":463,"line":29},[682],{"type":44,"tag":461,"props":683,"children":684},{},[685],{"type":50,"value":642},{"type":44,"tag":461,"props":687,"children":688},{"class":463,"line":493},[689],{"type":44,"tag":461,"props":690,"children":691},{},[692],{"type":50,"value":650},{"type":44,"tag":461,"props":694,"children":695},{"class":463,"line":503},[696],{"type":44,"tag":461,"props":697,"children":698},{},[699],{"type":50,"value":700},"    OnPrepareResponse = ctx =>\n",{"type":44,"tag":461,"props":702,"children":703},{"class":463,"line":512},[704],{"type":44,"tag":461,"props":705,"children":706},{},[707],{"type":50,"value":708},"    {\n",{"type":44,"tag":461,"props":710,"children":711},{"class":463,"line":520},[712],{"type":44,"tag":461,"props":713,"children":714},{},[715],{"type":50,"value":716},"        ctx.Context.Response.Headers.Append(\"Cache-Control\", \"public,max-age=31536000\");\n",{"type":44,"tag":461,"props":718,"children":719},{"class":463,"line":529},[720],{"type":44,"tag":461,"props":721,"children":722},{},[723],{"type":50,"value":724},"    }\n",{"type":44,"tag":461,"props":726,"children":727},{"class":463,"line":25},[728],{"type":44,"tag":461,"props":729,"children":730},{},[731],{"type":50,"value":666},{"type":44,"tag":167,"props":733,"children":735},{"id":734},"step-4-update-path-references-in-views-and-code",[736],{"type":50,"value":737},"Step 4: Update Path References in Views and Code",{"type":44,"tag":60,"props":739,"children":740},{},[741],{"type":50,"value":742},"Update all references to the old folder paths in Razor views, CSS files, and C# code.",{"type":44,"tag":60,"props":744,"children":745},{},[746],{"type":44,"tag":106,"props":747,"children":748},{},[749,751,757,759,765],{"type":50,"value":750},"Razor views — ",{"type":44,"tag":66,"props":752,"children":754},{"className":753},[],[755],{"type":50,"value":756},"~\u002FContent\u002F",{"type":50,"value":758}," and ",{"type":44,"tag":66,"props":760,"children":762},{"className":761},[],[763],{"type":50,"value":764},"~\u002FScripts\u002F",{"type":50,"value":766}," references:",{"type":44,"tag":60,"props":768,"children":769},{},[770],{"type":50,"value":771},"Before:",{"type":44,"tag":155,"props":773,"children":777},{"className":774,"code":775,"language":776,"meta":163,"style":163},"language-cshtml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Clink href=\"~\u002FContent\u002FSite.css\" rel=\"stylesheet\" \u002F>\n\u003Cscript src=\"~\u002FScripts\u002Fsite.js\">\u003C\u002Fscript>\n\u003Cimg src=\"~\u002FContent\u002Fimages\u002Flogo.png\" alt=\"Logo\" \u002F>\n","cshtml",[778],{"type":44,"tag":66,"props":779,"children":780},{"__ignoreMap":163},[781,789,797],{"type":44,"tag":461,"props":782,"children":783},{"class":463,"line":29},[784],{"type":44,"tag":461,"props":785,"children":786},{},[787],{"type":50,"value":788},"\u003Clink href=\"~\u002FContent\u002FSite.css\" rel=\"stylesheet\" \u002F>\n",{"type":44,"tag":461,"props":790,"children":791},{"class":463,"line":493},[792],{"type":44,"tag":461,"props":793,"children":794},{},[795],{"type":50,"value":796},"\u003Cscript src=\"~\u002FScripts\u002Fsite.js\">\u003C\u002Fscript>\n",{"type":44,"tag":461,"props":798,"children":799},{"class":463,"line":503},[800],{"type":44,"tag":461,"props":801,"children":802},{},[803],{"type":50,"value":804},"\u003Cimg src=\"~\u002FContent\u002Fimages\u002Flogo.png\" alt=\"Logo\" \u002F>\n",{"type":44,"tag":60,"props":806,"children":807},{},[808],{"type":50,"value":809},"After:",{"type":44,"tag":155,"props":811,"children":813},{"className":774,"code":812,"language":776,"meta":163,"style":163},"\u003Clink href=\"~\u002Fcss\u002FSite.css\" rel=\"stylesheet\" \u002F>\n\u003Cscript src=\"~\u002Fjs\u002Fsite.js\">\u003C\u002Fscript>\n\u003Cimg src=\"~\u002Fimages\u002Flogo.png\" alt=\"Logo\" \u002F>\n",[814],{"type":44,"tag":66,"props":815,"children":816},{"__ignoreMap":163},[817,825,833],{"type":44,"tag":461,"props":818,"children":819},{"class":463,"line":29},[820],{"type":44,"tag":461,"props":821,"children":822},{},[823],{"type":50,"value":824},"\u003Clink href=\"~\u002Fcss\u002FSite.css\" rel=\"stylesheet\" \u002F>\n",{"type":44,"tag":461,"props":826,"children":827},{"class":463,"line":493},[828],{"type":44,"tag":461,"props":829,"children":830},{},[831],{"type":50,"value":832},"\u003Cscript src=\"~\u002Fjs\u002Fsite.js\">\u003C\u002Fscript>\n",{"type":44,"tag":461,"props":834,"children":835},{"class":463,"line":503},[836],{"type":44,"tag":461,"props":837,"children":838},{},[839],{"type":50,"value":840},"\u003Cimg src=\"~\u002Fimages\u002Flogo.png\" alt=\"Logo\" \u002F>\n",{"type":44,"tag":60,"props":842,"children":843},{},[844,846,852,854,859],{"type":50,"value":845},"The ",{"type":44,"tag":66,"props":847,"children":849},{"className":848},[],[850],{"type":50,"value":851},"~\u002F",{"type":50,"value":853}," prefix continues to work in ASP.NET Core Razor views — it resolves to ",{"type":44,"tag":66,"props":855,"children":857},{"className":856},[],[858],{"type":50,"value":71},{"type":50,"value":97},{"type":44,"tag":60,"props":861,"children":862},{},[863],{"type":44,"tag":106,"props":864,"children":865},{},[866],{"type":50,"value":867},"CSS files — relative paths:",{"type":44,"tag":60,"props":869,"children":870},{},[871],{"type":50,"value":771},{"type":44,"tag":155,"props":873,"children":877},{"className":874,"code":875,"language":876,"meta":163,"style":163},"language-css shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","background-image: url('..\u002FContent\u002Fimages\u002Flogo.png');\n","css",[878],{"type":44,"tag":66,"props":879,"children":880},{"__ignoreMap":163},[881],{"type":44,"tag":461,"props":882,"children":883},{"class":463,"line":29},[884,890,896,901],{"type":44,"tag":461,"props":885,"children":887},{"style":886},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[888],{"type":50,"value":889},"background-image",{"type":44,"tag":461,"props":891,"children":893},{"style":892},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[894],{"type":50,"value":895},": url('.",{"type":44,"tag":461,"props":897,"children":899},{"style":898},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[900],{"type":50,"value":97},{"type":44,"tag":461,"props":902,"children":903},{"style":892},[904],{"type":50,"value":905},"\u002FContent\u002Fimages\u002Flogo.png');\n",{"type":44,"tag":60,"props":907,"children":908},{},[909],{"type":50,"value":809},{"type":44,"tag":155,"props":911,"children":913},{"className":874,"code":912,"language":876,"meta":163,"style":163},"background-image: url('..\u002Fimages\u002Flogo.png');\n",[914],{"type":44,"tag":66,"props":915,"children":916},{"__ignoreMap":163},[917],{"type":44,"tag":461,"props":918,"children":919},{"class":463,"line":29},[920,924,928,932],{"type":44,"tag":461,"props":921,"children":922},{"style":886},[923],{"type":50,"value":889},{"type":44,"tag":461,"props":925,"children":926},{"style":892},[927],{"type":50,"value":895},{"type":44,"tag":461,"props":929,"children":930},{"style":898},[931],{"type":50,"value":97},{"type":44,"tag":461,"props":933,"children":934},{"style":892},[935],{"type":50,"value":936},"\u002Fimages\u002Flogo.png');\n",{"type":44,"tag":60,"props":938,"children":939},{},[940],{"type":44,"tag":106,"props":941,"children":942},{},[943,945,951,952,958],{"type":50,"value":944},"C# code — ",{"type":44,"tag":66,"props":946,"children":948},{"className":947},[],[949],{"type":50,"value":950},"Server.MapPath",{"type":50,"value":758},{"type":44,"tag":66,"props":953,"children":955},{"className":954},[],[956],{"type":50,"value":957},"HostingEnvironment.MapPath",{"type":50,"value":959},":",{"type":44,"tag":60,"props":961,"children":962},{},[963],{"type":50,"value":771},{"type":44,"tag":155,"props":965,"children":967},{"className":453,"code":966,"language":455,"meta":163,"style":163},"var path = Server.MapPath(\"~\u002FApp_Data\u002Fdata.json\");\nvar path2 = HostingEnvironment.MapPath(\"~\u002FContent\u002Ftemplates\u002Freport.html\");\n",[968],{"type":44,"tag":66,"props":969,"children":970},{"__ignoreMap":163},[971,979],{"type":44,"tag":461,"props":972,"children":973},{"class":463,"line":29},[974],{"type":44,"tag":461,"props":975,"children":976},{},[977],{"type":50,"value":978},"var path = Server.MapPath(\"~\u002FApp_Data\u002Fdata.json\");\n",{"type":44,"tag":461,"props":980,"children":981},{"class":463,"line":493},[982],{"type":44,"tag":461,"props":983,"children":984},{},[985],{"type":50,"value":986},"var path2 = HostingEnvironment.MapPath(\"~\u002FContent\u002Ftemplates\u002Freport.html\");\n",{"type":44,"tag":60,"props":988,"children":989},{},[990],{"type":50,"value":809},{"type":44,"tag":155,"props":992,"children":994},{"className":453,"code":993,"language":455,"meta":163,"style":163},"\u002F\u002F Inject IWebHostEnvironment via constructor\nvar path = Path.Combine(_env.ContentRootPath, \"App_Data\", \"data.json\");\nvar path2 = Path.Combine(_env.WebRootPath, \"templates\", \"report.html\");\n",[995],{"type":44,"tag":66,"props":996,"children":997},{"__ignoreMap":163},[998,1006,1014],{"type":44,"tag":461,"props":999,"children":1000},{"class":463,"line":29},[1001],{"type":44,"tag":461,"props":1002,"children":1003},{},[1004],{"type":50,"value":1005},"\u002F\u002F Inject IWebHostEnvironment via constructor\n",{"type":44,"tag":461,"props":1007,"children":1008},{"class":463,"line":493},[1009],{"type":44,"tag":461,"props":1010,"children":1011},{},[1012],{"type":50,"value":1013},"var path = Path.Combine(_env.ContentRootPath, \"App_Data\", \"data.json\");\n",{"type":44,"tag":461,"props":1015,"children":1016},{"class":463,"line":503},[1017],{"type":44,"tag":461,"props":1018,"children":1019},{},[1020],{"type":50,"value":1021},"var path2 = Path.Combine(_env.WebRootPath, \"templates\", \"report.html\");\n",{"type":44,"tag":60,"props":1023,"children":1024},{},[1025,1027,1033,1035,1040,1041,1047,1049,1054],{"type":50,"value":1026},"Use ",{"type":44,"tag":66,"props":1028,"children":1030},{"className":1029},[],[1031],{"type":50,"value":1032},"ContentRootPath",{"type":50,"value":1034}," for private files outside ",{"type":44,"tag":66,"props":1036,"children":1038},{"className":1037},[],[1039],{"type":50,"value":71},{"type":50,"value":758},{"type":44,"tag":66,"props":1042,"children":1044},{"className":1043},[],[1045],{"type":50,"value":1046},"WebRootPath",{"type":50,"value":1048}," for public files inside ",{"type":44,"tag":66,"props":1050,"children":1052},{"className":1051},[],[1053],{"type":50,"value":71},{"type":50,"value":97},{"type":44,"tag":167,"props":1056,"children":1058},{"id":1057},"step-5-migrate-virtualpathprovider-to-ifileprovider",[1059],{"type":50,"value":1060},"Step 5: Migrate VirtualPathProvider to IFileProvider",{"type":44,"tag":60,"props":1062,"children":1063},{},[1064,1066,1071,1073,1078],{"type":50,"value":1065},"ASP.NET MVC's ",{"type":44,"tag":66,"props":1067,"children":1069},{"className":1068},[],[1070],{"type":50,"value":87},{"type":50,"value":1072}," has no direct replacement. ASP.NET Core uses ",{"type":44,"tag":66,"props":1074,"children":1076},{"className":1075},[],[1077],{"type":50,"value":95},{"type":50,"value":1079}," for the same purpose.",{"type":44,"tag":60,"props":1081,"children":1082},{},[1083],{"type":44,"tag":106,"props":1084,"children":1085},{},[1086],{"type":50,"value":1087},"Embedded resource serving:",{"type":44,"tag":60,"props":1089,"children":1090},{},[1091],{"type":50,"value":285},{"type":44,"tag":155,"props":1093,"children":1095},{"className":453,"code":1094,"language":455,"meta":163,"style":163},"\u002F\u002F Custom VirtualPathProvider registered in Global.asax\nHostingEnvironment.RegisterVirtualPathProvider(new EmbeddedResourceProvider());\n",[1096],{"type":44,"tag":66,"props":1097,"children":1098},{"__ignoreMap":163},[1099,1107],{"type":44,"tag":461,"props":1100,"children":1101},{"class":463,"line":29},[1102],{"type":44,"tag":461,"props":1103,"children":1104},{},[1105],{"type":50,"value":1106},"\u002F\u002F Custom VirtualPathProvider registered in Global.asax\n",{"type":44,"tag":461,"props":1108,"children":1109},{"class":463,"line":493},[1110],{"type":44,"tag":461,"props":1111,"children":1112},{},[1113],{"type":50,"value":1114},"HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedResourceProvider());\n",{"type":44,"tag":60,"props":1116,"children":1117},{},[1118],{"type":50,"value":302},{"type":44,"tag":155,"props":1120,"children":1122},{"className":453,"code":1121,"language":455,"meta":163,"style":163},"var embeddedProvider = new EmbeddedFileProvider(\n    typeof(Program).Assembly,\n    \"MyApp.EmbeddedAssets\");\n\napp.UseStaticFiles(new StaticFileOptions\n{\n    FileProvider = embeddedProvider,\n    RequestPath = \"\u002Fembedded\"\n});\n",[1123],{"type":44,"tag":66,"props":1124,"children":1125},{"__ignoreMap":163},[1126,1134,1142,1150,1157,1164,1171,1179,1187],{"type":44,"tag":461,"props":1127,"children":1128},{"class":463,"line":29},[1129],{"type":44,"tag":461,"props":1130,"children":1131},{},[1132],{"type":50,"value":1133},"var embeddedProvider = new EmbeddedFileProvider(\n",{"type":44,"tag":461,"props":1135,"children":1136},{"class":463,"line":493},[1137],{"type":44,"tag":461,"props":1138,"children":1139},{},[1140],{"type":50,"value":1141},"    typeof(Program).Assembly,\n",{"type":44,"tag":461,"props":1143,"children":1144},{"class":463,"line":503},[1145],{"type":44,"tag":461,"props":1146,"children":1147},{},[1148],{"type":50,"value":1149},"    \"MyApp.EmbeddedAssets\");\n",{"type":44,"tag":461,"props":1151,"children":1152},{"class":463,"line":512},[1153],{"type":44,"tag":461,"props":1154,"children":1155},{"emptyLinePlaceholder":497},[1156],{"type":50,"value":500},{"type":44,"tag":461,"props":1158,"children":1159},{"class":463,"line":520},[1160],{"type":44,"tag":461,"props":1161,"children":1162},{},[1163],{"type":50,"value":642},{"type":44,"tag":461,"props":1165,"children":1166},{"class":463,"line":529},[1167],{"type":44,"tag":461,"props":1168,"children":1169},{},[1170],{"type":50,"value":650},{"type":44,"tag":461,"props":1172,"children":1173},{"class":463,"line":25},[1174],{"type":44,"tag":461,"props":1175,"children":1176},{},[1177],{"type":50,"value":1178},"    FileProvider = embeddedProvider,\n",{"type":44,"tag":461,"props":1180,"children":1181},{"class":463,"line":545},[1182],{"type":44,"tag":461,"props":1183,"children":1184},{},[1185],{"type":50,"value":1186},"    RequestPath = \"\u002Fembedded\"\n",{"type":44,"tag":461,"props":1188,"children":1189},{"class":463,"line":554},[1190],{"type":44,"tag":461,"props":1191,"children":1192},{},[1193],{"type":50,"value":666},{"type":44,"tag":60,"props":1195,"children":1196},{},[1197],{"type":50,"value":1198},"Mark resources as embedded in the project file:",{"type":44,"tag":155,"props":1200,"children":1204},{"className":1201,"code":1202,"language":1203,"meta":163,"style":163},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003CItemGroup>\n  \u003CEmbeddedResource Include=\"EmbeddedAssets\u002F**\u002F*\" \u002F>\n\u003C\u002FItemGroup>\n","xml",[1205],{"type":44,"tag":66,"props":1206,"children":1207},{"__ignoreMap":163},[1208,1216,1224],{"type":44,"tag":461,"props":1209,"children":1210},{"class":463,"line":29},[1211],{"type":44,"tag":461,"props":1212,"children":1213},{},[1214],{"type":50,"value":1215},"\u003CItemGroup>\n",{"type":44,"tag":461,"props":1217,"children":1218},{"class":463,"line":493},[1219],{"type":44,"tag":461,"props":1220,"children":1221},{},[1222],{"type":50,"value":1223},"  \u003CEmbeddedResource Include=\"EmbeddedAssets\u002F**\u002F*\" \u002F>\n",{"type":44,"tag":461,"props":1225,"children":1226},{"class":463,"line":503},[1227],{"type":44,"tag":461,"props":1228,"children":1229},{},[1230],{"type":50,"value":1231},"\u003C\u002FItemGroup>\n",{"type":44,"tag":60,"props":1233,"children":1234},{},[1235],{"type":44,"tag":106,"props":1236,"children":1237},{},[1238],{"type":50,"value":1239},"Custom file system sources:",{"type":44,"tag":60,"props":1241,"children":1242},{},[1243],{"type":50,"value":285},{"type":44,"tag":155,"props":1245,"children":1247},{"className":453,"code":1246,"language":455,"meta":163,"style":163},"public class DatabaseVirtualPathProvider : VirtualPathProvider\n{\n    public override bool FileExists(string virtualPath) { \u002F* ... *\u002F }\n    public override VirtualFile GetFile(string virtualPath) { \u002F* ... *\u002F }\n}\n",[1248],{"type":44,"tag":66,"props":1249,"children":1250},{"__ignoreMap":163},[1251,1259,1266,1274,1282],{"type":44,"tag":461,"props":1252,"children":1253},{"class":463,"line":29},[1254],{"type":44,"tag":461,"props":1255,"children":1256},{},[1257],{"type":50,"value":1258},"public class DatabaseVirtualPathProvider : VirtualPathProvider\n",{"type":44,"tag":461,"props":1260,"children":1261},{"class":463,"line":493},[1262],{"type":44,"tag":461,"props":1263,"children":1264},{},[1265],{"type":50,"value":650},{"type":44,"tag":461,"props":1267,"children":1268},{"class":463,"line":503},[1269],{"type":44,"tag":461,"props":1270,"children":1271},{},[1272],{"type":50,"value":1273},"    public override bool FileExists(string virtualPath) { \u002F* ... *\u002F }\n",{"type":44,"tag":461,"props":1275,"children":1276},{"class":463,"line":512},[1277],{"type":44,"tag":461,"props":1278,"children":1279},{},[1280],{"type":50,"value":1281},"    public override VirtualFile GetFile(string virtualPath) { \u002F* ... *\u002F }\n",{"type":44,"tag":461,"props":1283,"children":1284},{"class":463,"line":520},[1285],{"type":44,"tag":461,"props":1286,"children":1287},{},[1288],{"type":50,"value":1289},"}\n",{"type":44,"tag":60,"props":1291,"children":1292},{},[1293],{"type":50,"value":302},{"type":44,"tag":155,"props":1295,"children":1297},{"className":453,"code":1296,"language":455,"meta":163,"style":163},"public class DatabaseFileProvider : IFileProvider\n{\n    public IFileInfo GetFileInfo(string subpath) { \u002F* ... *\u002F }\n    public IDirectoryContents GetDirectoryContents(string subpath) { \u002F* ... *\u002F }\n    public IChangeToken Watch(string filter) => NullChangeToken.Singleton;\n}\n",[1298],{"type":44,"tag":66,"props":1299,"children":1300},{"__ignoreMap":163},[1301,1309,1316,1324,1332,1340],{"type":44,"tag":461,"props":1302,"children":1303},{"class":463,"line":29},[1304],{"type":44,"tag":461,"props":1305,"children":1306},{},[1307],{"type":50,"value":1308},"public class DatabaseFileProvider : IFileProvider\n",{"type":44,"tag":461,"props":1310,"children":1311},{"class":463,"line":493},[1312],{"type":44,"tag":461,"props":1313,"children":1314},{},[1315],{"type":50,"value":650},{"type":44,"tag":461,"props":1317,"children":1318},{"class":463,"line":503},[1319],{"type":44,"tag":461,"props":1320,"children":1321},{},[1322],{"type":50,"value":1323},"    public IFileInfo GetFileInfo(string subpath) { \u002F* ... *\u002F }\n",{"type":44,"tag":461,"props":1325,"children":1326},{"class":463,"line":512},[1327],{"type":44,"tag":461,"props":1328,"children":1329},{},[1330],{"type":50,"value":1331},"    public IDirectoryContents GetDirectoryContents(string subpath) { \u002F* ... *\u002F }\n",{"type":44,"tag":461,"props":1333,"children":1334},{"class":463,"line":520},[1335],{"type":44,"tag":461,"props":1336,"children":1337},{},[1338],{"type":50,"value":1339},"    public IChangeToken Watch(string filter) => NullChangeToken.Singleton;\n",{"type":44,"tag":461,"props":1341,"children":1342},{"class":463,"line":529},[1343],{"type":44,"tag":461,"props":1344,"children":1345},{},[1346],{"type":50,"value":1289},{"type":44,"tag":60,"props":1348,"children":1349},{},[1350],{"type":50,"value":1351},"Register the custom provider:",{"type":44,"tag":155,"props":1353,"children":1355},{"className":453,"code":1354,"language":455,"meta":163,"style":163},"app.UseStaticFiles(new StaticFileOptions\n{\n    FileProvider = new DatabaseFileProvider(connectionString),\n    RequestPath = \"\u002Fdynamic\"\n});\n",[1356],{"type":44,"tag":66,"props":1357,"children":1358},{"__ignoreMap":163},[1359,1366,1373,1381,1389],{"type":44,"tag":461,"props":1360,"children":1361},{"class":463,"line":29},[1362],{"type":44,"tag":461,"props":1363,"children":1364},{},[1365],{"type":50,"value":642},{"type":44,"tag":461,"props":1367,"children":1368},{"class":463,"line":493},[1369],{"type":44,"tag":461,"props":1370,"children":1371},{},[1372],{"type":50,"value":650},{"type":44,"tag":461,"props":1374,"children":1375},{"class":463,"line":503},[1376],{"type":44,"tag":461,"props":1377,"children":1378},{},[1379],{"type":50,"value":1380},"    FileProvider = new DatabaseFileProvider(connectionString),\n",{"type":44,"tag":461,"props":1382,"children":1383},{"class":463,"line":512},[1384],{"type":44,"tag":461,"props":1385,"children":1386},{},[1387],{"type":50,"value":1388},"    RequestPath = \"\u002Fdynamic\"\n",{"type":44,"tag":461,"props":1390,"children":1391},{"class":463,"line":520},[1392],{"type":44,"tag":461,"props":1393,"children":1394},{},[1395],{"type":50,"value":666},{"type":44,"tag":60,"props":1397,"children":1398},{},[1399,1401,1406],{"type":50,"value":1400},"To compose multiple providers (equivalent to chaining ",{"type":44,"tag":66,"props":1402,"children":1404},{"className":1403},[],[1405],{"type":50,"value":87},{"type":50,"value":1407}," instances):",{"type":44,"tag":155,"props":1409,"children":1411},{"className":453,"code":1410,"language":455,"meta":163,"style":163},"var compositeProvider = new CompositeFileProvider(\n    builder.Environment.WebRootFileProvider,\n    new EmbeddedFileProvider(typeof(Program).Assembly),\n    new DatabaseFileProvider(connectionString));\n\napp.UseStaticFiles(new StaticFileOptions\n{\n    FileProvider = compositeProvider\n});\n",[1412],{"type":44,"tag":66,"props":1413,"children":1414},{"__ignoreMap":163},[1415,1423,1431,1439,1447,1454,1461,1468,1476],{"type":44,"tag":461,"props":1416,"children":1417},{"class":463,"line":29},[1418],{"type":44,"tag":461,"props":1419,"children":1420},{},[1421],{"type":50,"value":1422},"var compositeProvider = new CompositeFileProvider(\n",{"type":44,"tag":461,"props":1424,"children":1425},{"class":463,"line":493},[1426],{"type":44,"tag":461,"props":1427,"children":1428},{},[1429],{"type":50,"value":1430},"    builder.Environment.WebRootFileProvider,\n",{"type":44,"tag":461,"props":1432,"children":1433},{"class":463,"line":503},[1434],{"type":44,"tag":461,"props":1435,"children":1436},{},[1437],{"type":50,"value":1438},"    new EmbeddedFileProvider(typeof(Program).Assembly),\n",{"type":44,"tag":461,"props":1440,"children":1441},{"class":463,"line":512},[1442],{"type":44,"tag":461,"props":1443,"children":1444},{},[1445],{"type":50,"value":1446},"    new DatabaseFileProvider(connectionString));\n",{"type":44,"tag":461,"props":1448,"children":1449},{"class":463,"line":520},[1450],{"type":44,"tag":461,"props":1451,"children":1452},{"emptyLinePlaceholder":497},[1453],{"type":50,"value":500},{"type":44,"tag":461,"props":1455,"children":1456},{"class":463,"line":529},[1457],{"type":44,"tag":461,"props":1458,"children":1459},{},[1460],{"type":50,"value":642},{"type":44,"tag":461,"props":1462,"children":1463},{"class":463,"line":25},[1464],{"type":44,"tag":461,"props":1465,"children":1466},{},[1467],{"type":50,"value":650},{"type":44,"tag":461,"props":1469,"children":1470},{"class":463,"line":545},[1471],{"type":44,"tag":461,"props":1472,"children":1473},{},[1474],{"type":50,"value":1475},"    FileProvider = compositeProvider\n",{"type":44,"tag":461,"props":1477,"children":1478},{"class":463,"line":554},[1479],{"type":44,"tag":461,"props":1480,"children":1481},{},[1482],{"type":50,"value":666},{"type":44,"tag":167,"props":1484,"children":1486},{"id":1485},"step-6-configure-files-outside-wwwroot",[1487],{"type":50,"value":1488},"Step 6: Configure Files Outside wwwroot",{"type":44,"tag":60,"props":1490,"children":1491},{},[1492,1494,1499,1501,1506,1508,1514],{"type":50,"value":1493},"Files outside ",{"type":44,"tag":66,"props":1495,"children":1497},{"className":1496},[],[1498],{"type":50,"value":71},{"type":50,"value":1500}," are not served by default. To serve files from additional directories, add a second ",{"type":44,"tag":66,"props":1502,"children":1504},{"className":1503},[],[1505],{"type":50,"value":79},{"type":50,"value":1507}," call with an explicit ",{"type":44,"tag":66,"props":1509,"children":1511},{"className":1510},[],[1512],{"type":50,"value":1513},"PhysicalFileProvider",{"type":50,"value":959},{"type":44,"tag":155,"props":1516,"children":1518},{"className":453,"code":1517,"language":455,"meta":163,"style":163},"app.UseStaticFiles(); \u002F\u002F Default: serves from wwwroot\u002F\n\napp.UseStaticFiles(new StaticFileOptions\n{\n    FileProvider = new PhysicalFileProvider(\n        Path.Combine(builder.Environment.ContentRootPath, \"StaticAssets\")),\n    RequestPath = \"\u002Fassets\"\n});\n",[1519],{"type":44,"tag":66,"props":1520,"children":1521},{"__ignoreMap":163},[1522,1530,1537,1544,1551,1559,1567,1575],{"type":44,"tag":461,"props":1523,"children":1524},{"class":463,"line":29},[1525],{"type":44,"tag":461,"props":1526,"children":1527},{},[1528],{"type":50,"value":1529},"app.UseStaticFiles(); \u002F\u002F Default: serves from wwwroot\u002F\n",{"type":44,"tag":461,"props":1531,"children":1532},{"class":463,"line":493},[1533],{"type":44,"tag":461,"props":1534,"children":1535},{"emptyLinePlaceholder":497},[1536],{"type":50,"value":500},{"type":44,"tag":461,"props":1538,"children":1539},{"class":463,"line":503},[1540],{"type":44,"tag":461,"props":1541,"children":1542},{},[1543],{"type":50,"value":642},{"type":44,"tag":461,"props":1545,"children":1546},{"class":463,"line":512},[1547],{"type":44,"tag":461,"props":1548,"children":1549},{},[1550],{"type":50,"value":650},{"type":44,"tag":461,"props":1552,"children":1553},{"class":463,"line":520},[1554],{"type":44,"tag":461,"props":1555,"children":1556},{},[1557],{"type":50,"value":1558},"    FileProvider = new PhysicalFileProvider(\n",{"type":44,"tag":461,"props":1560,"children":1561},{"class":463,"line":529},[1562],{"type":44,"tag":461,"props":1563,"children":1564},{},[1565],{"type":50,"value":1566},"        Path.Combine(builder.Environment.ContentRootPath, \"StaticAssets\")),\n",{"type":44,"tag":461,"props":1568,"children":1569},{"class":463,"line":25},[1570],{"type":44,"tag":461,"props":1571,"children":1572},{},[1573],{"type":50,"value":1574},"    RequestPath = \"\u002Fassets\"\n",{"type":44,"tag":461,"props":1576,"children":1577},{"class":463,"line":545},[1578],{"type":44,"tag":461,"props":1579,"children":1580},{},[1581],{"type":50,"value":666},{"type":44,"tag":60,"props":1583,"children":1584},{},[1585,1587,1592,1594,1599,1601,1606],{"type":50,"value":1586},"Skip this step if all public assets fit under ",{"type":44,"tag":66,"props":1588,"children":1590},{"className":1589},[],[1591],{"type":50,"value":71},{"type":50,"value":1593},". Serving files from outside ",{"type":44,"tag":66,"props":1595,"children":1597},{"className":1596},[],[1598],{"type":50,"value":71},{"type":50,"value":1600}," adds complexity — prefer moving files into ",{"type":44,"tag":66,"props":1602,"children":1604},{"className":1603},[],[1605],{"type":50,"value":71},{"type":50,"value":1607}," when possible.",{"type":44,"tag":167,"props":1609,"children":1611},{"id":1610},"step-7-remove-legacy-folder-references",[1612],{"type":50,"value":1613},"Step 7: Remove Legacy Folder References",{"type":44,"tag":60,"props":1615,"children":1616},{},[1617],{"type":50,"value":1618},"Search the codebase for remaining references to the old folder structure and clean them up:",{"type":44,"tag":179,"props":1620,"children":1621},{},[1622,1640,1659,1684,1701,1712],{"type":44,"tag":183,"props":1623,"children":1624},{},[1625,1627,1632,1633,1638],{"type":50,"value":1626},"Remove ",{"type":44,"tag":66,"props":1628,"children":1630},{"className":1629},[],[1631],{"type":50,"value":191},{"type":50,"value":366},{"type":44,"tag":66,"props":1634,"children":1636},{"className":1635},[],[1637],{"type":50,"value":202},{"type":50,"value":1639}," folders (now empty after move)",{"type":44,"tag":183,"props":1641,"children":1642},{},[1643,1644,1649,1651,1657],{"type":50,"value":1626},{"type":44,"tag":66,"props":1645,"children":1647},{"className":1646},[],[1648],{"type":50,"value":87},{"type":50,"value":1650}," registration from ",{"type":44,"tag":66,"props":1652,"children":1654},{"className":1653},[],[1655],{"type":50,"value":1656},"Global.asax",{"type":50,"value":1658}," or startup",{"type":44,"tag":183,"props":1660,"children":1661},{},[1662,1663,1668,1670,1675,1677,1682],{"type":50,"value":1626},{"type":44,"tag":66,"props":1664,"children":1666},{"className":1665},[],[1667],{"type":50,"value":249},{"type":50,"value":1669}," entries from ",{"type":44,"tag":66,"props":1671,"children":1673},{"className":1672},[],[1674],{"type":50,"value":241},{"type":50,"value":1676}," (if ",{"type":44,"tag":66,"props":1678,"children":1680},{"className":1679},[],[1681],{"type":50,"value":241},{"type":50,"value":1683}," is being removed)",{"type":44,"tag":183,"props":1685,"children":1686},{},[1687,1688,1693,1694,1699],{"type":50,"value":1626},{"type":44,"tag":66,"props":1689,"children":1691},{"className":1690},[],[1692],{"type":50,"value":957},{"type":50,"value":758},{"type":44,"tag":66,"props":1695,"children":1697},{"className":1696},[],[1698],{"type":50,"value":950},{"type":50,"value":1700}," calls",{"type":44,"tag":183,"props":1702,"children":1703},{},[1704,1705,1711],{"type":50,"value":1626},{"type":44,"tag":66,"props":1706,"children":1708},{"className":1707},[],[1709],{"type":50,"value":1710},"HostingEnvironment.RegisterVirtualPathProvider",{"type":50,"value":1700},{"type":44,"tag":183,"props":1713,"children":1714},{},[1715],{"type":50,"value":1716},"Update any build scripts or CI pipelines that reference old paths",{"type":44,"tag":53,"props":1718,"children":1720},{"id":1719},"success-criteria",[1721],{"type":50,"value":1722},"Success Criteria",{"type":44,"tag":179,"props":1724,"children":1725},{},[1726,1758,1776,1807,1831,1854,1872,1895],{"type":44,"tag":183,"props":1727,"children":1728},{},[1729,1734,1736,1742,1743,1749,1750,1756],{"type":44,"tag":66,"props":1730,"children":1732},{"className":1731},[],[1733],{"type":50,"value":71},{"type":50,"value":1735}," folder exists with ",{"type":44,"tag":66,"props":1737,"children":1739},{"className":1738},[],[1740],{"type":50,"value":1741},"css\u002F",{"type":50,"value":366},{"type":44,"tag":66,"props":1744,"children":1746},{"className":1745},[],[1747],{"type":50,"value":1748},"js\u002F",{"type":50,"value":366},{"type":44,"tag":66,"props":1751,"children":1753},{"className":1752},[],[1754],{"type":50,"value":1755},"images\u002F",{"type":50,"value":1757}," subfolders following Core conventions",{"type":44,"tag":183,"props":1759,"children":1760},{},[1761,1767,1769,1774],{"type":44,"tag":66,"props":1762,"children":1764},{"className":1763},[],[1765],{"type":50,"value":1766},"app.UseStaticFiles()",{"type":50,"value":1768}," registered in ",{"type":44,"tag":66,"props":1770,"children":1772},{"className":1771},[],[1773],{"type":50,"value":440},{"type":50,"value":1775}," before routing middleware",{"type":44,"tag":183,"props":1777,"children":1778},{},[1779,1781,1786,1787,1792,1794,1800,1801],{"type":50,"value":1780},"All ",{"type":44,"tag":66,"props":1782,"children":1784},{"className":1783},[],[1785],{"type":50,"value":756},{"type":50,"value":758},{"type":44,"tag":66,"props":1788,"children":1790},{"className":1789},[],[1791],{"type":50,"value":764},{"type":50,"value":1793}," references updated to ",{"type":44,"tag":66,"props":1795,"children":1797},{"className":1796},[],[1798],{"type":50,"value":1799},"~\u002Fcss\u002F",{"type":50,"value":758},{"type":44,"tag":66,"props":1802,"children":1804},{"className":1803},[],[1805],{"type":50,"value":1806},"~\u002Fjs\u002F",{"type":44,"tag":183,"props":1808,"children":1809},{},[1810,1815,1816,1821,1823,1829],{"type":44,"tag":66,"props":1811,"children":1813},{"className":1812},[],[1814],{"type":50,"value":950},{"type":50,"value":128},{"type":44,"tag":66,"props":1817,"children":1819},{"className":1818},[],[1820],{"type":50,"value":957},{"type":50,"value":1822}," replaced with ",{"type":44,"tag":66,"props":1824,"children":1826},{"className":1825},[],[1827],{"type":50,"value":1828},"IWebHostEnvironment",{"type":50,"value":1830}," paths",{"type":44,"tag":183,"props":1832,"children":1833},{},[1834,1839,1840,1845,1846,1852],{"type":44,"tag":66,"props":1835,"children":1837},{"className":1836},[],[1838],{"type":50,"value":87},{"type":50,"value":1822},{"type":44,"tag":66,"props":1841,"children":1843},{"className":1842},[],[1844],{"type":50,"value":95},{"type":50,"value":128},{"type":44,"tag":66,"props":1847,"children":1849},{"className":1848},[],[1850],{"type":50,"value":1851},"EmbeddedFileProvider",{"type":50,"value":1853}," (if applicable)",{"type":44,"tag":183,"props":1855,"children":1856},{},[1857,1859,1864,1866],{"type":50,"value":1858},"Custom MIME types from ",{"type":44,"tag":66,"props":1860,"children":1862},{"className":1861},[],[1863],{"type":50,"value":241},{"type":50,"value":1865}," migrated to ",{"type":44,"tag":66,"props":1867,"children":1869},{"className":1868},[],[1870],{"type":50,"value":1871},"FileExtensionContentTypeProvider",{"type":44,"tag":183,"props":1873,"children":1874},{},[1875,1877,1882,1883,1888,1890],{"type":50,"value":1876},"No remaining references to ",{"type":44,"tag":66,"props":1878,"children":1880},{"className":1879},[],[1881],{"type":50,"value":191},{"type":50,"value":366},{"type":44,"tag":66,"props":1884,"children":1886},{"className":1885},[],[1887],{"type":50,"value":202},{"type":50,"value":1889},", or ",{"type":44,"tag":66,"props":1891,"children":1893},{"className":1892},[],[1894],{"type":50,"value":87},{"type":44,"tag":183,"props":1896,"children":1897},{},[1898],{"type":50,"value":1899},"Project builds without errors",{"type":44,"tag":1901,"props":1902,"children":1903},"style",{},[1904],{"type":50,"value":1905},"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);}",{"items":1907,"total":2100},[1908,1930,1949,1970,1985,2002,2013,2026,2041,2056,2075,2088],{"slug":1909,"name":1909,"fn":1910,"description":1911,"org":1912,"tags":1913,"stars":1927,"repoUrl":1928,"updatedAt":1929},"rushstack-best-practices","manage Rush monorepos with best practices","Provides best practices and guidance for working with Rush monorepos. Use when the user is working in a Rush-based repository, asks about Rush commands (install, update, build, rebuild), needs help with project selection, dependency management, build caching, subspace configuration, or troubleshooting Rush-specific issues.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1914,1917,1920,1921,1924],{"name":1915,"slug":1916,"type":15},"Engineering","engineering",{"name":1918,"slug":1919,"type":15},"Local Development","local-development",{"name":9,"slug":8,"type":15},{"name":1922,"slug":1923,"type":15},"Project Management","project-management",{"name":1925,"slug":1926,"type":15},"Rush","rush",6484,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frushstack","2026-04-06T18:34:44.965032",{"slug":1931,"name":1931,"fn":1932,"description":1933,"org":1934,"tags":1935,"stars":1946,"repoUrl":1947,"updatedAt":1948},"azure-ai-agents-persistent-dotnet","build AI agents with Azure .NET SDK","Azure AI Agents Persistent SDK for .NET. Low-level SDK for creating and managing AI agents with threads, messages, runs, and tools. Use for agent CRUD, conversation threads, streaming responses, function calling, file search, and code interpreter. Triggers: \"PersistentAgentsClient\", \"persistent agents\", \"agent threads\", \"agent runs\", \"streaming agents\", \"function calling agents .NET\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1936,1937,1940,1943],{"name":17,"slug":18,"type":15},{"name":1938,"slug":1939,"type":15},"Agents","agents",{"name":1941,"slug":1942,"type":15},"Azure","azure",{"name":1944,"slug":1945,"type":15},"LLM","llm",2804,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fskills","2026-07-03T16:32:10.297433",{"slug":1950,"name":1950,"fn":1951,"description":1952,"org":1953,"tags":1954,"stars":1946,"repoUrl":1947,"updatedAt":1969},"azure-ai-anomalydetector-java","build anomaly detection applications with Java","Build anomaly detection applications with Azure AI Anomaly Detector SDK for Java. Use when implementing univariate\u002Fmultivariate anomaly detection, time-series analysis, or AI-powered monitoring.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1955,1958,1959,1962,1965,1966],{"name":1956,"slug":1957,"type":15},"Analytics","analytics",{"name":1941,"slug":1942,"type":15},{"name":1960,"slug":1961,"type":15},"Data Analysis","data-analysis",{"name":1963,"slug":1964,"type":15},"Java","java",{"name":9,"slug":8,"type":15},{"name":1967,"slug":1968,"type":15},"Monitoring","monitoring","2026-05-13T06:14:16.261754",{"slug":1971,"name":1971,"fn":1972,"description":1973,"org":1974,"tags":1975,"stars":1946,"repoUrl":1947,"updatedAt":1984},"azure-ai-contentsafety-java","build content moderation applications with Azure AI","Build content moderation applications with Azure AI Content Safety SDK for Java. Use when implementing text\u002Fimage analysis, blocklist management, or harm detection for hate, violence, sexual content, and self-harm.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1976,1979,1980,1981],{"name":1977,"slug":1978,"type":15},"AI Infrastructure","ai-infrastructure",{"name":1941,"slug":1942,"type":15},{"name":1963,"slug":1964,"type":15},{"name":1982,"slug":1983,"type":15},"Security","security","2026-07-07T06:53:31.293235",{"slug":1986,"name":1986,"fn":1987,"description":1988,"org":1989,"tags":1990,"stars":1946,"repoUrl":1947,"updatedAt":2001},"azure-ai-contentsafety-py","detect harmful content with Azure AI Content Safety","Azure AI Content Safety SDK for Python. Use for detecting harmful content in text and images with multi-severity classification.\nTriggers: \"azure-ai-contentsafety\", \"ContentSafetyClient\", \"content moderation\", \"harmful content\", \"text analysis\", \"image analysis\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1991,1992,1995,1996,1997,2000],{"name":1941,"slug":1942,"type":15},{"name":1993,"slug":1994,"type":15},"Compliance","compliance",{"name":1944,"slug":1945,"type":15},{"name":9,"slug":8,"type":15},{"name":1998,"slug":1999,"type":15},"Python","python",{"name":1982,"slug":1983,"type":15},"2026-07-18T05:14:23.017504",{"slug":2003,"name":2003,"fn":2004,"description":2005,"org":2006,"tags":2007,"stars":1946,"repoUrl":1947,"updatedAt":2012},"azure-ai-language-conversations-py","implement conversational language understanding with Python","Implement Conversational Language Understanding (CLU) using the azure-ai-language-conversations Python SDK. Use when working with ConversationAnalysisClient to analyze conversation intent and entities, building NLP features, or integrating language understanding into applications.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2008,2009,2010,2011],{"name":1956,"slug":1957,"type":15},{"name":1941,"slug":1942,"type":15},{"name":1944,"slug":1945,"type":15},{"name":1998,"slug":1999,"type":15},"2026-07-31T05:54:29.068751",{"slug":2014,"name":2014,"fn":2015,"description":2016,"org":2017,"tags":2018,"stars":1946,"repoUrl":1947,"updatedAt":2025},"azure-ai-translation-text-py","translate text using Azure AI services","Azure AI Text Translation SDK for real-time text translation, transliteration, language detection, and dictionary lookup. Use for translating text content in applications.\nTriggers: \"text translation\", \"translator\", \"translate text\", \"transliterate\", \"TextTranslationClient\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2019,2022,2023,2024],{"name":2020,"slug":2021,"type":15},"API Development","api-development",{"name":1941,"slug":1942,"type":15},{"name":9,"slug":8,"type":15},{"name":1998,"slug":1999,"type":15},"2026-07-18T05:14:16.988376",{"slug":2027,"name":2027,"fn":2028,"description":2029,"org":2030,"tags":2031,"stars":1946,"repoUrl":1947,"updatedAt":2040},"azure-ai-vision-imageanalysis-py","analyze images with Azure AI Vision","Azure AI Vision Image Analysis SDK for captions, tags, objects, OCR, people detection, and smart cropping. Use for computer vision and image understanding tasks.\nTriggers: \"image analysis\", \"computer vision\", \"OCR\", \"object detection\", \"ImageAnalysisClient\", \"image caption\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2032,2033,2036,2039],{"name":1941,"slug":1942,"type":15},{"name":2034,"slug":2035,"type":15},"Computer Vision","computer-vision",{"name":2037,"slug":2038,"type":15},"Images","images",{"name":1998,"slug":1999,"type":15},"2026-07-18T05:14:18.007737",{"slug":2042,"name":2042,"fn":2043,"description":2044,"org":2045,"tags":2046,"stars":1946,"repoUrl":1947,"updatedAt":2055},"azure-appconfiguration-java","manage configuration with Azure App Configuration","Azure App Configuration SDK for Java. Centralized application configuration management with key-value settings, feature flags, and snapshots.\nTriggers: \"ConfigurationClient java\", \"app configuration java\", \"feature flag java\", \"configuration setting java\", \"azure config java\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2047,2048,2051,2054],{"name":1941,"slug":1942,"type":15},{"name":2049,"slug":2050,"type":15},"Configuration","configuration",{"name":2052,"slug":2053,"type":15},"Feature Flags","feature-flags",{"name":1963,"slug":1964,"type":15},"2026-07-03T16:32:01.278468",{"slug":2057,"name":2057,"fn":2058,"description":2059,"org":2060,"tags":2061,"stars":1946,"repoUrl":1947,"updatedAt":2074},"azure-cosmos-rust","build applications with Azure Cosmos DB","Azure Cosmos DB library for Rust (NoSQL API). Document CRUD, containers, and globally distributed data.\nTriggers: \"cosmos db rust\", \"CosmosClient rust\", \"document crud rust\", \"NoSQL rust\", \"partition key rust\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2062,2065,2068,2071],{"name":2063,"slug":2064,"type":15},"Cosmos DB","cosmos-db",{"name":2066,"slug":2067,"type":15},"Database","database",{"name":2069,"slug":2070,"type":15},"NoSQL","nosql",{"name":2072,"slug":2073,"type":15},"Rust","rust","2026-07-31T05:54:27.021432",{"slug":2076,"name":2076,"fn":2058,"description":2077,"org":2078,"tags":2079,"stars":1946,"repoUrl":1947,"updatedAt":2087},"azure-cosmos-ts","Azure Cosmos DB JavaScript\u002FTypeScript SDK (@azure\u002Fcosmos) for data plane operations. Use for CRUD operations on documents, queries, bulk operations, and container management. Triggers: \"Cosmos DB\", \"@azure\u002Fcosmos\", \"CosmosClient\", \"document CRUD\", \"NoSQL queries\", \"bulk operations\", \"partition key\", \"container.items\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2080,2081,2082,2083,2084],{"name":2063,"slug":2064,"type":15},{"name":2066,"slug":2067,"type":15},{"name":9,"slug":8,"type":15},{"name":2069,"slug":2070,"type":15},{"name":2085,"slug":2086,"type":15},"TypeScript","typescript","2026-07-03T16:31:19.368382",{"slug":2089,"name":2089,"fn":2090,"description":2091,"org":2092,"tags":2093,"stars":1946,"repoUrl":1947,"updatedAt":2099},"azure-data-tables-java","build table storage applications with Java","Build table storage applications with Azure Tables SDK for Java. Use when working with Azure Table Storage or Cosmos DB Table API for NoSQL key-value data, schemaless storage, or structured data at scale.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2094,2095,2096,2097,2098],{"name":1941,"slug":1942,"type":15},{"name":2063,"slug":2064,"type":15},{"name":2066,"slug":2067,"type":15},{"name":1963,"slug":1964,"type":15},{"name":2069,"slug":2070,"type":15},"2026-05-13T06:14:17.582229",267,{"items":2102,"total":2190},[2103,2113,2127,2144,2154,2165,2176],{"slug":2104,"name":2104,"fn":2105,"description":2106,"org":2107,"tags":2108,"stars":25,"repoUrl":26,"updatedAt":2112},"converting-to-cpm","migrate .NET projects to Central Package Management","Converts .NET projects and solutions to NuGet Central Package Management (CPM) with Directory.Packages.props. Use when the user wants to centralize, convert, align, or sync NuGet package versions across multiple projects, resolve version conflicts or mismatches, or get versions consistent across a solution or repository. Also triggers when packages are out of sync or drifting across projects.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2109,2110,2111],{"name":17,"slug":18,"type":15},{"name":9,"slug":8,"type":15},{"name":23,"slug":24,"type":15},"2026-07-18T05:14:13.971821",{"slug":2114,"name":2114,"fn":2115,"description":2116,"org":2117,"tags":2118,"stars":25,"repoUrl":26,"updatedAt":2126},"creating-winforms-custom-controls","create custom WinForms controls","Creates custom controls and UserControls for modern WinForms (.NET 6+). Use when deriving from Control, UserControl, Button, TextBox, or other base controls, implementing custom rendering with OnPaint overrides, creating composite controls with child control composition, adding custom properties with [Browsable], [Category], or [DefaultValue] attributes for Designer support, implementing INotifyPropertyChanged for control properties, handling Layout\u002FLayoutEngine for custom sizing, creating scrollable controls with AutoScrollMinSize, implementing dark mode theming, or building List\u002FGrid\u002FTree-like controls. Also triggers for \"custom UserControl\", \"derive from Control\", \"owner-drawn control\", \"Designer properties\", \"[Browsable] attribute\", \"custom WinForms control\", \"LayoutEngine\", \"AutoScroll control\", and \"themed control\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2119,2120,2123],{"name":17,"slug":18,"type":15},{"name":2121,"slug":2122,"type":15},"Windows","windows",{"name":2124,"slug":2125,"type":15},"WinUI","winui","2026-07-03T16:31:30.1325",{"slug":2128,"name":2128,"fn":2129,"description":2130,"org":2131,"tags":2132,"stars":25,"repoUrl":26,"updatedAt":2143},"managing-winforms-high-dpi-layout","design high-DPI responsive WinForms layouts","Implements WinForms high-DPI fluent layouts using TableLayoutPanel, FlowLayoutPanel, and DPI-aware design patterns. Use when creating responsive form layouts that must scale across different DPI settings, implementing Per Monitor V2 (PerMonitorV2) DPI awareness, working with TableLayoutPanel.RowStyles\u002FColumnStyles, using FlowLayoutPanel for dynamic layouts, replacing fixed pixel positioning with container-based layout, troubleshooting DPI scaling issues, or structuring nested layout containers. Also triggers for \"TableLayoutPanel\", \"FlowLayoutPanel\", \"high DPI WinForms\", \"PerMonitorV2\", \"DPI aware layout\", \"responsive WinForms\", \"scale UI\", \"AutoScaleMode\", and \"DPI scaling\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2133,2136,2139,2142],{"name":2134,"slug":2135,"type":15},"Design","design",{"name":2137,"slug":2138,"type":15},"Desktop","desktop",{"name":2140,"slug":2141,"type":15},"UI Components","ui-components",{"name":2121,"slug":2122,"type":15},"2026-07-18T05:14:12.982806",{"slug":2145,"name":2145,"fn":2146,"description":2147,"org":2148,"tags":2149,"stars":25,"repoUrl":26,"updatedAt":2153},"managing-winforms-mvvm","implement MVVM pattern in WinForms","Implements MVVM pattern in WinForms applications (.NET 8+) with ViewModels, Commands, and DataContext. Use when user explicitly requests MVVM implementation, setting up ViewModel with INotifyPropertyChanged or ObservableObject, implementing ICommand or RelayCommand, wiring Form.DataContext, binding controls to ViewModel properties, creating Commands for button clicks, or separating business logic from UI code. Also triggers for \"WinForms MVVM\", \"ViewModel in WinForms\", \"INotifyPropertyChanged\", \"DataContext binding\", \"Command pattern WinForms\", \"ObservableObject\", \"RelayCommand\", and \"testable WinForms\". Also use when fixing existing MVVM code or when guided by winforms-feature-adoption scenario. DO NOT USE FOR: automatic application during version upgrades (opt-in only).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2150,2151,2152],{"name":17,"slug":18,"type":15},{"name":2121,"slug":2122,"type":15},{"name":2124,"slug":2125,"type":15},"2026-07-18T05:14:11.951511",{"slug":2155,"name":2155,"fn":2156,"description":2157,"org":2158,"tags":2159,"stars":25,"repoUrl":26,"updatedAt":2164},"migrating-aspnet-framework-to-core","migrate ASP.NET Framework to Core","Orchestrates migration of ASP.NET Framework (System.Web) MVC and WebAPI projects to ASP.NET Core. Covers only old .NET Framework web projects — not applicable to ASP.NET Core or modern .NET web projects (those are already on the target stack). Defines the ordered phase sequence (project file, host, config, DI, controllers, middleware, auth, views, cleanup), satellite skill dispatch, and migration unit breakdown for both in-place and side-by-side modes. Use when executing a task that upgrades a project with System.Web dependencies, HttpModules, HttpHandlers, MVC controllers, WebAPI controllers, or Global.asax. Also triggers for \"migrate ASP.NET to Core\", \"upgrade MVC project\", \"convert WebAPI to ASP.NET Core\". Not applicable to class libraries unless they directly reference System.Web.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2160,2161,2162,2163],{"name":17,"slug":18,"type":15},{"name":20,"slug":21,"type":15},{"name":13,"slug":14,"type":15},{"name":23,"slug":24,"type":15},"2026-07-03T16:30:55.581898",{"slug":2166,"name":2166,"fn":2167,"description":2168,"org":2169,"tags":2170,"stars":25,"repoUrl":26,"updatedAt":2175},"migrating-documentdb-to-cosmos","migrate DocumentDB to Cosmos DB","Migrates from the deprecated Microsoft.Azure.DocumentDB SDK (V2) to the modern Microsoft.Azure.Cosmos SDK (V3) for Azure Cosmos DB. Use ONLY when Microsoft.Azure.DocumentDB has been flagged as deprecated or obsolete and must be replaced — not for version-bump scenarios where the V2 SDK is still supported.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2171,2172,2173,2174],{"name":1941,"slug":1942,"type":15},{"name":2063,"slug":2064,"type":15},{"name":2066,"slug":2067,"type":15},{"name":23,"slug":24,"type":15},"2026-07-03T16:31:21.932144",{"slug":2177,"name":2177,"fn":2178,"description":2179,"org":2180,"tags":2181,"stars":25,"repoUrl":26,"updatedAt":2189},"migrating-global-asax","migrate Global.asax to ASP.NET Core middleware","Migrates Global.asax application lifecycle events to ASP.NET Core middleware, startup configuration, and Program.cs. Use when upgrading ASP.NET Framework apps containing Global.asax or Global.asax.cs files. Triggers for \"migrate Global.asax\", \"convert application events\", \"move Application_Start to Program.cs\", \"replace Global.asax with middleware\", and ASP.NET-to-Core migration involving request lifecycle, error handling, or session management.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2182,2184,2185,2186],{"name":20,"slug":2183,"type":15},"aspnet-core",{"name":9,"slug":8,"type":15},{"name":23,"slug":24,"type":15},{"name":2187,"slug":2188,"type":15},"Modernization","modernization","2026-07-07T06:54:34.226435",19]