I have configuration reading in my program class as below
if (azureAdSettings != null)
{
builder.Configuration["AzureAd:Instance"] = azureAdSettings.Instance;
builder.Configuration["AzureAd:Domain"] = azureAdSettings.Domain;
builder.Configuration["AzureAd:TenantId"] = azureAdSettings.TenantId;
builder.Configuration["AzureAd:ClientId"] = azureAdSettings.ClientId;
builder.Configuration["AzureAd:ClientSecret"] = azureAdSettings.ClientSecret;
if (!string.IsNullOrEmpty(azureAdSettings?.ClientId))
{
string[] scopes = builder.Configuration["Graph:Scopes"].Split(",");
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(scopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
.AddInMemoryTokenCaches();
}
}
Is there any way to check here if (azureAdSettings != null)
if db is already created. The issue is the custom middleware is throwing issue at this line here return context?.AzureAdSettings?.FirstOrDefault();
This is complete Program.cs file
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages().AddMicrosoftIdentityUI();
builder.Services.ConfigureApplicationCookie(options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(15);
options.LoginPath = "/Account/Login";
options.LogoutPath = "/MicrosoftIdentity/Account/SignedOut";
options.AccessDeniedPath = "/Account/AccessDenied";
options.SlidingExpiration = false;
});
builder.Services.Configure<CookiePolicyOptions>(o =>
{
o.Secure = CookieSecurePolicy.Always;
});
builder.Services.AddControllersWithViews();
builder.Services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; });
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
List<CultureInfo> supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-GB"),
new CultureInfo("ar-QA")
};
options.DefaultRequestCulture = new RequestCulture(culture: "en-GB", uiCulture: "en-GB");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
builder.Services.AddDbContext<ApplicationDBContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"),
sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
});
});
builder.Services.AddScoped<IViewRenderService, ViewRenderService>();
builder.Services.AddScoped<IClaimsTransformation, ClaimsTransformer>();
builder.Services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
builder.Services.AddMvc().AddDataAnnotationsLocalization(o =>
{
o.DataAnnotationLocalizerProvider = (type, factory) =>
{
return factory.Create(typeof(SharedResource));
};
});
builder.Services.AddSession();
builder.Services.AddElmah<SqlErrorLog>(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection");
options.OnPermissionCheck = context => context.User.IsInRole("BusinessAdmin");
});
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<ApplicationDBContext>();
await context.Database.MigrateAsync();
await DbInitializer.SeedData(context, services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred during migration and seeding");
}
}
// Load Azure AD settings
var azureAdSettings = StartupHelper.LoadAzureAdSettings(builder.Configuration);
if (azureAdSettings != null)
{
builder.Configuration["AzureAd:Instance"] = azureAdSettings.Instance;
builder.Configuration["AzureAd:Domain"] = azureAdSettings.Domain;
builder.Configuration["AzureAd:TenantId"] = azureAdSettings.TenantId;
builder.Configuration["AzureAd:ClientId"] = azureAdSettings.ClientId;
builder.Configuration["AzureAd:ClientSecret"] = azureAdSettings.ClientSecret;
if (!string.IsNullOrEmpty(azureAdSettings?.ClientId))
{
string[] scopes = builder.Configuration["Graph:Scopes"].Split(",");
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(scopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
.AddInMemoryTokenCaches();
}
}
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error/AccessDenied");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseMiddleware<AzureAdSettingsMiddleware>();
if (!string.IsNullOrEmpty(azureAdSettings?.ClientId))
{
app.UseAuthentication();
app.UseAuthorization();
}
app.UseElmah();
var options = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(options.Value);
app.UseSession();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Account}/{action=Login}/{id?}");
app.MapRazorPages();
app.Run();
And this is my custom middleware where the error is coming.
public class AzureAdSettingsMiddleware
{
private readonly RequestDelegate _next;
public AzureAdSettingsMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context, ApplicationDBContext dbContext, IConfiguration configuration, IServiceProvider serviceProvider)
{
var settings = await dbContext.AzureAdSettings.AsNoTracking().OrderByDescending(x => x.Id).FirstOrDefaultAsync();
if (settings == null && !context.Request.Path.StartsWithSegments("/Settings/Setup"))
{
context.Response.Redirect("/Settings/Setup");
return;
}
else if (settings != null && !context.Request.Path.StartsWithSegments("/Settings/AdSetupComplete"))
{
var azureAdClientId = configuration["AzureAd:ClientId"];
if (azureAdClientId != settings.ClientId)
{
context.Response.Headers.Append("X-Message", "Your AD is set up. Please restart the application");
var redirectUrl = "/Settings/AdSetupComplete?redirected=true";
context.Response.Redirect(redirectUrl);
return;
}
}
await _next(context);
}
}
public class StartupHelper
{
public static AzureAdSettings LoadAzureAdSettings(IConfiguration configuration)
{
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDBContext>();
optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
using (var context = new ApplicationDBContext(optionsBuilder.Options))
{
return context.AzureAdSettings.AsNoTracking().FirstOrDefault();
}
}
}
And this is my db initilizer file complete https://pastebin.com/H7XC68Pv. Is there any way to check db is created befor reading settings from db, else i am promting user to enter their creds. Thanks!