问题描述
我使用自定义 WebApplicationFactory 对我的 razor Web 应用程序进行了集成测试:
public class CustomWebApplicationFactory<TStartup>
: WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var descriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<GenericDbContext>));
services.Remove(descriptor);
services.AddDbContext<GenericDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
});
var sp = services.BuildServiceProvider();
using var scope = sp.CreateScope();
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetrequiredService<GenericDbContext>();
var logger = scopedServices
.GetrequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
db.Database.EnsureCreated();
try
{
Utilities.InitializeDbForTests(db);
}
catch (Exception ex)
{
logger.LogError(ex,"An error occurred seeding the " +
"database with test messages. Error: {Message}",ex.Message);
}
});
}
}
在 TStartup 中,我传递了这个启动配置服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor,HttpContextAccessor>();
//AzureADB2C
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAdB2C(options => Configuration.Bind("Authentication:AzureAdB2C",options))
.AddCookie(options =>
{
options.Cookie.SameSite = SameSiteMode.None;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.IsEssential = true;
//options.ExpireTimeSpan = TimeSpan.FromDays(365);
});
//AzureADB2C
//Simple
//services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
// .AddAzureADB2C(options => Configuration.Bind("Authentication:AzureAdB2C",options));
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false; // = context => true; //When set to true,TempData will not work unless the user opts in.
options.MinimumSameSitePolicy = SameSiteMode.Unspecified; //If we dont do the hack for chrome/safari,this should be set to 'None'
options.Secure = CookieSecurePolicy.Always;
//Hack for Chrome/Safari. May not be needed in future
options.OnAppendCookie = cookieContext =>
CheckSameSite(cookieContext.Context,cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
CheckSameSite(cookieContext.Context,cookieContext.CookieOptions);
});
services.AddRouting(options => {
options.LowercaseUrls = true;
//options.AppendTrailingSlash = false;
});
//Response Caching
services.AddResponseCaching();
//With conditional runtime compilation
IMvcBuilder builder = services.AddRazorPages()
.AddRazorPagesOptions(options =>
{
//Sitemap
options.Conventions.AddAreaPageRoute("xxxxxx","/xxxxxx","xxxxxx.xml");
options.Conventions.AddAreaPageRoute("xxxxxx","xxxxxx/xxxxxx.xml");
options.Conventions.AddAreaPageRoute("xxxxxx","xxxxxx/xxxxxx.xml");
options.Conventions.AuthorizeAreaFolder("xxxxxx","/");
options.Conventions.AuthorizeAreaFolder("xxxxxx","/");
options.Conventions.AuthorizeAreaFolder("xxxxxxx","/","xxxxx");
//options.Conventions.AuthorizeAreaFolder("xxxx","/");
//options.Conventions.AuthorizeAreaFolder("xxxxx","/");
options.Conventions.AuthorizeAreaPage("xxxx","/xxxxx");
//password reset
options.Conventions.AllowAnonymousToAreaPage("xxxxx","/xxxxx");
options.Conventions.AllowAnonymousToAreaPage("xxxxx","/xxxx");
//Checkout and 3DS pages
options.Conventions.AllowAnonymousToAreaPage("xxxxx","/xxxxx");
});
services.AddMemoryCache();
//CACHE for tokens
// Adds a default in-memory implementation of IdistributedCache.
services.AdddistributedMemoryCache();
//services.AddSession();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromHours(1);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Unspecified;// SameSiteMode.None;
//options.IdleTimeout = TimeSpan.FromDays(365);
});
services.AddDbContext<IGenericDbContext,GenericDbContext>(options => options.UsesqlServer(Configuration.GetConnectionString("GenericDbConnection")));
}
就像我在自定义 WebApplicationFactory 中删除 dbContextOption 一样,我想删除 AuthorizeAreaFolder 或覆盖“services.AddRazorPages().AddRazorPagesOptions()”以允许集成测试在不伪造授权的情况下获取或发布页面。
解决方法
AddRazorPagesOptions
本质上只是在服务集合上配置了 RazorPagesOptions
,所以它等价于如下:
services.Configure<RazorPagesOptions>(options =>
{
options.Conventions.AuthorizeAreaFolder("xxxxxx","/");
// …
});
这也意味着为了改变约定,你可以重新配置RazorPagesOptions
,直接修改约定集合。不幸的是,IPageConvention
类型是私有的,因此您无法直接查找由 AuthorizeAreaFolder
添加的条目并使用 RemoveType
方法删除它们。但是,您可以clear 整个集合以完全删除所有约定:
services.Configure<RazorPagesOptions>(options =>
{
options.Conventions.Clear();
});