I'm using modular monolith layered app architecture to combine Main with few modules. Modules have razor CSHTML pages which works locally in https://localhost/ i.e. local dev environment. All default page paths are working good. i.e. Via Menu Contributor in Main module, accessing the pages works perfectly. But when deployed to IIS server in Azure VM, via devOps script, same app menu page paths gives 404 error. While diagnosing, have these json responses for the corresponding diagnostic controller method code for your reference. I've also attached the csproj files of the Main module and Lms module. Is there anything I'm setting inadvertently wrong while deploying?
localhost pic: https://prime2dev.blob.core.windows.net/general/host/delete-this-temp/localhost.jpg azure IIS pic: https://prime2dev.blob.core.windows.net/general/host/delete-this-temp/Azure-IIS-Hosted.jpg
if I use this code on server API side to diagnose: [HttpGet("check-razor-pages")] public IActionResult CheckRazorPages() { var pages = _actionDescriptorProvider.ActionDescriptors.Items .OfType<Microsoft.AspNetCore.Mvc.RazorPages.PageActionDescriptor>() .Where(p => p.ViewEnginePath.Contains("Lms") || p.ViewEnginePath.Contains("Events") || p.ViewEnginePath.Contains("Case")) .Select(p => new { ViewEnginePath = p.ViewEnginePath, RelativePath = p.RelativePath, DisplayName = p.DisplayName, RouteTemplate = p.AttributeRouteInfo?.Template, // ← THIS IS CRITICAL RouteValues = p.RouteValues }) .ToList();
return Ok(new
{[https://playwarestudios-my.sharepoint.com/:f:/g/personal/pwsadmin_playwarestudios_onmicrosoft_com/EgMOorRpfYhLikQCbbSlcJIBFC01j6KJVpuq7762tz04dA?e=ZyUqtE](here)
TotalPages = pages.Count,
Pages = pages,
NoRouteTemplates = pages.Where(p => string.IsNullOrEmpty(p.RouteTemplate)).ToList()
});
}
always gives no results.
refer to csproj files and MainWebmodule,cs and LmsWebModule.cs code shared here
- Exception message and full stack trace:
- Steps to reproduce the issue:
2 Answer(s)
-
0
hi
Can you share your full module code that includes the problem Razor page?
liming.ma@volosoft.com
Thanks.
-
0
- Solution The 404 on IIS for module Razor Pages typically means the pages are not discovered at runtime on the server. In ABP modular monoliths this happens when the module’s Razor Pages and embedded resources aren’t registered or published correctly, or when middleware order misses virtual files.
Apply the checklist below and republish:
- Ensure each module’s Web module depends on AbpAspNetCoreMvcModule and registers embedded Razor Pages:
[DependsOn( typeof(AbpAspNetCoreMvcModule) // + other dependencies... )] public class LmsWebModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { // Allow ABP to find embedded Razor pages of this module Configure<AbpVirtualFileSystemOptions>(options => { options.FileSets.AddEmbedded<LmsWebModule>(); }); context.Services .AddRazorPages() .AddApplicationPart(typeof(LmsWebModule).Assembly); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); // IMPORTANT for ABP virtual/embedded files (including Razor pages/views) app.UseAbp(); // ensures UseAbpVirtualFiles inside the pipeline app.UseConfiguredEndpoints(); // maps Razor Pages } }- In the main web host module, also ensure AddRazorPages().AddApplicationPart(...) for each module that contains pages (or rely on conventional discovery by referencing the module assembly).
- In ConfigureServices of the main web host, if you use Razor Class Libraries, you can also add:
services.AddControllersWithViews() .AddApplicationPart(typeof(LmsWebModule).Assembly) .AddControllersAsServices(); services.AddRazorPages() .AddApplicationPart(typeof(LmsWebModule).Assembly);- Make sure the module assemblies that contain the Razor Pages are referenced by the host web project so they’re copied to publish output. In the host .csproj:
<ItemGroup> <ProjectReference Include="..\..\modules\Lms\src\Lms.Web\Lms.Web.csproj" /> <!-- repeat for other modules that have Razor Pages --> </ItemGroup>If you pack modules as NuGet packages, ensure the package is referenced by the host and contains the compiled Razor views (RCL).
- Verify wwwroot and ABP virtual files are served in IIS:
- In the host’s module initialization:
- app.UseStaticFiles();
- app.MapAbpStaticAssets(); (ABP 9+ web apps) or app.UseAbp() which registers UseAbpVirtualFiles.
- Confirm that the publish includes static content:
- In the host’s module initialization:
<ItemGroup> <Content Include="wwwroot\**\*"> <CopyToPublishDirectory>Always</CopyToPublishDirectory> </Content> </ItemGroup>- Remove IIS WebDAV for non-GET verbs if you also see 405 on POST/PUT/DELETE (commonly blocks form posts or antiforgery flows): Web.config snippet under system.webServer:
<modules> <remove name="WebDAVModule" /> </modules> <handlers> <remove name="WebDAV" /> </handlers>- Publishing notes:
- Use dotnet publish for Release and deploy the publish folder to IIS. Ensure all module assemblies are present in the publish output.
- If you see “multiple publish output files with same relative path” for Razor Pages across modules (e.g., duplicate Pages/_ViewImports.cshtml), either rename conflicting files or set:
<PropertyGroup> <ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles> </PropertyGroup>in the host web project as a workaround.- Middleware order sanity check (host application):
app.UseCorrelationId(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseAbp(); // registers ABP middleware incl. virtual files and localization, etc. app.UseConfiguredEndpoints(); // ABP maps controllers and Razor Pages- Diagnose on server:
- Hitting your check-razor-pages endpoint returned empty because PageActionDescriptors weren’t discovered. After applying AddRazorPages().AddApplicationPart(moduleAsm) and ensuring assemblies are present, re-check: you should see ViewEnginePath/RelativePath entries and non-empty count. Also verify that AttributeRouteInfo can be null for Razor Pages; rely on ViewEnginePath/RouteValues instead of RouteTemplate.
If these steps are applied, the same module Razor Pages that work locally will be discovered and served on IIS.
- Sources
- https://abp.io/docs/latest/framework/architecture/modularity/basics
- https://abp.io/docs/latest/solution-templates/layered-web-application/deployment/deployment-iis
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.