提问人:nerdalert 提问时间:11/12/2023 最后编辑:nerdalert 更新时间:11/13/2023 访问量:45
.NET Razor 页面,回发时清除作用域依赖项注入属性
.NET Razor pages, scoped dependency injection properties cleared on postback
问:
我正在尝试在我的 Razor 页面项目上实现持久性存储。我需要的是,在我的页面上回发时,不应清除属性值。我正在通过依赖注入来做到这一点。我将存储属性值的类注入到页面模型的构造函数中,并打算在回发后重新填充页面变量。
我打算使用AddScoped,但似乎在回发时类值被清除了。如果我使用 AddSingleton,那么是的,类值不会被清除,但我不希望它们在用户导航到另一个页面时保持填充状态。我希望在用户位于特定页面上并在该页面上执行回发时填充这些值,并在刷新页面或导航到另一个页面时清除这些值。这样,在进行回发时,我可以用类变量重新填充页面变量。
在程序.cs中
builder.Services.AddScoped<IDataService, DataService>();
我的界面
public interface IDataService
{
Models.User? User { get; set; }
byte[]? LogoData { get; set; }
public byte[]? SignatureData { get; set; }
}
我的页面
public Models.User? User { get; set; }
public byte[]? LogoData { get; set; }
public byte[]? SignatureData { get; set; }
public ProfileModel(ILogger<ProfileModel> loggerService, IDataService dataService)
{
_loggerService = loggerService;
_dataService = dataService;
}
当我在页面上提交表单时,会点击以下方法,但是如果我在开头放置一个断点并检查我的_dataService类的内容,则一切都为 null。
public async Task<IActionResult> OnPostRecreateApiKeyAsync()
{
...
}
我的整个程序.cs文件:
var builder = WebApplication.CreateBuilder(args);
// If needed, Clear default providers
builder.Logging.ClearProviders();
// Use Serilog
builder.Host.UseSerilog((hostContext, services, configuration) => {
configuration
.WriteTo.File("serilog.txt")
.WriteTo.Console();
});
// Add services to the container.
builder.Services.AddRazorPages();
// register my dbcontext from data project
builder.Services.ConfigureService(builder.Configuration);
// register services
builder.Services.AddTransient<IApiKeyService, ApiKeyService>();
builder.Services.AddTransient<IStripeService, StripeService>();
builder.Services.AddTransient<IInvoiceService, InvoiceService>();
builder.Services.AddTransient<IUserService, UserService>();
builder.Services.AddScoped<IDataService, DataService>();
// add support for Auth0
builder.Services
.AddAuth0WebAppAuthentication(options => {
options.Domain = builder.Configuration["Auth0:Domain"];
options.ClientId = builder.Configuration["Auth0:ClientId"];
options.Scope = "openid profile email";
});
// protect these pages
builder.Services.AddRazorPages(options =>
{
options.Conventions.AuthorizePage("/account/profile");
options.Conventions.AuthorizePage("/account/usage");
options.Conventions.AuthorizePage("/account/logout");
options.Conventions.AuthorizePage("/account/billing/history");
options.Conventions.AuthorizePage("/account/billing/paymentmethods");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
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.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
答:
0赞
Ruikai Feng
11/13/2023
#1
当我在页面上提交表单时,点击了以下方法,但如果我将 开头的断点,检查我的_dataService的内容 class 一切都是 null。
builder.Services.AddScoped<IDataService, DataService>();
在 asp.net 核心中,作用域服务为一个请求保留相同的实例,当您提交表单时,您正在发出另一个请求,您将获得另一个 DataService 实例,而不是您在 GET 处理程序中设置属性的实例
public void OnGet()
{
LogoData = ....//read from your other service?
HttpContext.Session.Set("LogoData", LogoData);
}
public void OnPost()
{
if(HttpContext.Session.TryGetValue("LogoData",out var logodata))
{
LogoData = logodata;
}
}
您可以尝试将数据存储到会话中,每次发送时清除会话 GET 请求
添加 Reuired 服务:
builder.Services.AddSession();
中间件:
app.UseSession();
app.Use(async (context, next) =>
{
//when you refresh the page or navigate to another page,you are always sending get request
// you could add a hidden input to record your current page,read it from HttpContext.Request.Form and check target page if you want clear session when you send post request to another page
if (context.Request.Method == "GET")
{
context.Session.Clear();
}
await next.Invoke();
});
评论
Startup
ConfigureServices
builder
builder.UseDefaultServiceProvider( o => { o.ValidateScopes = true; ValidateOnBuild = true; } )
ValidateScopes