我有一个简单的 .NET6 OData API,默认配置启用批处理。API 使用默认 VS 模板中的 IdentityServer 进行配置。
Program.cs
var builder = WebApplication.CreateBuilder(args);
if (builder.Configuration.GetSection("ConnectionStrings:Active").Value == "Postgres")
{
var connectionString = builder.Configuration.GetConnectionString("Postgres");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(connectionString));
}
else
{
var connectionString = builder.Configuration.GetConnectionString("SQLServer");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
}
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequiredLength = 8;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
builder.Services.AddIdentityServer(options =>
{
options.UserInteraction.LoginUrl = "/login";
options.UserInteraction.LogoutUrl = "/logout";
})
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.AddLocalization();
builder.Services.AddControllersWithViews(options =>
{
options.ModelBinderProviders.Insert(0, new CustomModelBinderProvider());
})
.AddOData(opt =>
{
var batchHandler = new DefaultODataBatchHandler();
batchHandler.MessageQuotas.MaxNestingDepth = 2;
batchHandler.MessageQuotas.MaxReceivedMessageSize = 100;
batchHandler.MessageQuotas.MaxOperationsPerChangeset = 10;
opt.AddRouteComponents("oapi",
new OdataModelBuilder().GetEDM(),
services => services.AddSingleton<ISearchBinder, ODataSearch>());
opt.AddRouteComponents("oapi_b",
new OdataModelBuilder().GetEDM(),
batchHandler);
opt.EnableQueryFeatures();
})
.AddDataAnnotationsLocalization(options =>
{
options.DataAnnotationLocalizerProvider = (type, factory) =>
factory.Create(typeof(SharedResources));
})
.AddRazorRuntimeCompilation();
builder.Services.AddRazorPages();
builder.Services.AddAutoMapper(System.Reflection.Assembly.GetExecutingAssembly());
builder.Services.AddHttpContextAccessor();
if (builder.Environment.IsDevelopment())
{
builder.Services.AddScoped<DummySeedService>();
}
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
app.UseODataRouteDebug();
using (var scope = app.Services.CreateScope())
{
var seedService = scope.ServiceProvider.GetRequiredService<DummySeedService>();
await seedService.Seed();
}
}
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.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseODataBatching();
app.UseRouting();
app.UseMiddleware<ODataTestMiddleware>();
var supportedCultures = new[] { "en-US", "ar-SY" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
问题
发出$batch
请求后,当执行掉出UseODataBatching
中间件时,中间件中的HttpContext
属性IHttpContextAccessor
变为null,这会触发中间件NullReferenceException
中的a,IdentityServer
从而500
为所有请求返回
Requests
(来自邮递员):
{
"requests": [
{
"id": "{{$guid}}",
"url": "Patients(1)",
"method": "GET",
"headers": {
"content-type": "application/json"
}
},
{
"id": "{{$guid}}",
"url": "Patients(2)",
"method": "GET",
"headers": {
"content-type": "application/json"
}
}
]
}
Responses
:
{
"responses": [
{
"id": "8a4dac81-2662-472b-bef9-273401a53cfb",
"status": 500,
"headers": {}
},
{
"id": "933c6bbe-db67-4526-8199-2eedc176dc7b",
"status": 500,
"headers": {}
}
]
}
删除IdentityServer
中间件时,批处理请求通过并返回200
两个请求都没有问题。
作为测试,我写了一个测试中间件ODataTestMiddleware
public class ODataTestMiddleware
{
private readonly RequestDelegate requestDelegate;
public ODataTestMiddleware(RequestDelegate requestDelegate)
{
this.requestDelegate = requestDelegate;
}
public async Task InvokeAsync(HttpContext httpContext, IHttpContextAccessor contextAccessor)
{
await requestDelegate(httpContext);
}
}
并且IHttpContextAccessor.HttpContext
在这里也是空的。
我在 OData 存储库中看到了这个问题IHttpContextAccessor.HttpContext 在 odata 批处理调用中执行时返回 null,但我使用的是ASP.NET Core版本,所以我不知道两者在实现方面的区别。
有没有我可以尝试的解决方法?感谢您的时间。