I know there are a lot of moving parts to consider here but I thought I’d post and see if anyone had any thoughts. I am running into an issue with the load time of my View being slow. I added logging at various points within the controller and the controller code executes in around 12ms. So I added logging at the top of my View. There is consistently a 4-6 second delay from the time my controller code completes to the time the view begins to load:
OnActionExecuted – 7/23/2024 3:17:08 PM <- Last entry from end of ActionResult method.
RenderBegin – 7/23/2024 3:17:14 PM <- At the top of _Layout
This is the code from Program.cs:
var builder = WebApplication.CreateBuilder(args);
connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
// Get the scopes from the configuration (appsettings.json)
var initialScopes = builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
builder.Services.AddFeatureManagement();
builder.Services.AddScoped<PreserveStateFilter>();
builder.Services.AddHangfire(configuration => configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(connectionString));
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddRazorOptions(opt => {
opt.ViewLocationFormats.Add("/Views/Forms/{0}" + RazorViewEngine.ViewExtension);
opt.ViewLocationFormats.Add("/Views/ArchivedForms/{0}" + RazorViewEngine.ViewExtension);
});
builder.Services.AddSession(options => {});
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddHangfireServer();
builder.Services.AddRazorPages()
.AddMicrosoftIdentityUI();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
Serilog.Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(app.Configuration)
.WriteTo.MSSqlServer(
connectionString: connectionString,
sinkOptions: new MSSqlServerSinkOptions
{
TableName = "Log",
AutoCreateSqlTable = true
})
.CreateLogger();
// Add configuration to helper functions to allow access to app settings
BaseModel.AppSettingsConfigure(app.Services.GetRequiredService<IConfiguration>());
FormsPortal.AppSettingsConfigure(app.Services.GetRequiredService<IConfiguration>());
HelperFunctions.AppSettingsConfigure(app.Services.GetRequiredService<IConfiguration>());
EmailUtility.AppSettingsConfigure(app.Services.GetRequiredService<IConfiguration>());
FormsJob.AppSettingsConfigure(app.Services.GetRequiredService<IConfiguration>());
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthorization();
app.Use(async (context, next) =>
{
if (context.Request.Path.Equals("/hangfire", StringComparison.OrdinalIgnoreCase)
&& !context.User.Identity.IsAuthenticated)
{
await context.ChallengeAsync();
return;
}
await next();
});
app.UseHangfireDashboard("/hangfire", new DashboardOptions()
{
AppPath = "/Forms",
Authorization = new[] { new HangfireAuthorizationFilter() },
IgnoreAntiforgeryToken = true
});
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{encryptedId?}");
app.MapRazorPages();
app.StartRecurringJobs();
app.Run();