I have a new .NET Core 3.1 app and am struggling with the concept of Middleware. From reading around, it seems the order of including different middlewares is important. I currently have several problems which I can't seem to solve:
This is how I'm bootstrapping the app. It feels like something is overriding the settings:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<DataProtectionTokenProviderOptions>(options =>
options.TokenLifespan = TimeSpan.FromDays(2));
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30);
});
services.AddControllersWithViews();
services.AddTransient<IUserStore<User>, UserStore>();
services.AddTransient<IRoleStore<IdentityRole>, RoleStore>();
services.AddRazorPages();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = new PathString("/login");
options.AccessDeniedPath = new PathString("/error/denied");
options.LogoutPath = new PathString("/log-off");
options.ExpireTimeSpan = TimeSpan.FromDays(60);
options.SlidingExpiration = true;
options.Cookie.HttpOnly = true;
options.Cookie.Name = "MyCookie";
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.Cookie.SameSite = SameSiteMode.Lax;
});
services.AddIdentity<User, IdentityRole>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
})
.AddUserStore<UserStore>()
.AddRoleStore<RoleStore>()
.AddDefaultTokenProviders();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddElmah<SqlErrorLog>(options =>
{
options.ConnectionString = Configuration.GetConnectionString("MyApp");
options.CheckPermissionAction = (context)=>{
return context.User.Identity.IsAuthenticated && context.User.IsInRole(RoleHelper.SuperAdmin);
};
options.Path = "/elmah";
});
services.AddSingleton<IAppConfiguration, AppConfiguration>(e => Configuration.GetSection("AppConfig")
.Get<AppConfiguration>());
OptionsConfigurationServiceCollectionExtensions.Configure<DbHelper>(services, Configuration.GetSection("ConnectionStrings"));
services.AddHttpContextAccessor();
}
public void ConfigureContainer(ContainerBuilder builder)
{
// wire up using autofac specific APIs here
builder.Register(context => new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, MyDetailsViewModel>();
})).AsSelf().SingleInstance();
builder.RegisterModule(new RegistrationModule()); // separate assembly, wires up autofac registrations
builder.Register(c =>
{
//This resolves a new context that can be used later.
var context = c.Resolve<IComponentContext>();
var config = context.Resolve<MapperConfiguration>();
return config.CreateMapper(context.Resolve);
})
.As<IMapper>()
.InstancePerLifetimeScope();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
// debugger shows this section is called, but I never see the error page.
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseRouteDebugger();
}
else
{
app.UseExceptionHandler("/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();
}
app.UseSession();
app.UseElmah();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
var cookiePolicyOptions = new CookiePolicyOptions
{
Secure = CookieSecurePolicy.SameAsRequest,
MinimumSameSitePolicy = SameSiteMode.None
};
app.UseCookiePolicy(cookiePolicyOptions);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Guest}/{action=Index}/{id?}");
endpoints.MapRazorPages();
endpoints.MapControllers();
});
app.UseStatusCodePages(async ctx =>
{
//Re-execute the request so the user gets the error page
string originalPath = ctx.HttpContext.Request.Path.Value;
switch (ctx.HttpContext.Response.StatusCode)
{
case 401:
//Re-execute the request so the user gets the error page
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/denied";
break;
case 412:
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/expired-account";
break;
case 404:
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/not-found";
break;
case 500:
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/not-found";
break;
}
});
DapperExtensions.DapperExtensions.SetMappingAssemblies(new[]
{
Assembly.GetAssembly(typeof(MyApp.Domain.Model.Note)),
Assembly.GetExecutingAssembly()
});
}
In regards to the order of your middleware, there is a problem with it.
There is a section in the Microsoft docs dedicated to the order of middleware, I suggest reading it.
As for your middleware, the correct order would be:
app.UseHttpsRedirection();
app.UseStatusCodePages(async ctx =>
{
// Omitted for brevity.
});
app.UseStaticFiles();
var cookiePolicyOptions = new CookiePolicyOptions
{
// Omitted for brevity.
};
app.UseCookiePolicy(cookiePolicyOptions);
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
// If the app uses session state, call Session Middleware after Cookie
// Policy Middleware and before MVC Middleware.
app.UseSession();
app.UseElmah(); // Not sure about this one. I don't know what it's supposed to do?
app.UseEndpoints(endpoints =>
{
// Omitted for brevity.
});
DapperExtensions.DapperExtensions.SetMappingAssemblies(new[]
{
// Omitted for brevity.
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With