如何在核心 razor 网站中存储 int userId asp.net

How to store an int userId in asp.net core razor website

提问人:user14554500 提问时间:11/5/2023 更新时间:11/12/2023 访问量:80

问:

严重努力寻找一个体面的解决方案来跨多个页面访问 int userId 值

所以我不是专家。就在你觉得自己有能力的时候,这样的问题就出现了。

我有一个使用 Identity(使用 VS 2022)的 asp.net 核心 razor Web 应用项目。Identity 正在工作,但我真的想要一个 int userId 而不是一个字符串,但完全放弃了尝试修改 Identity 以使用 int 作为 userId 而不是默认字符串。

因此,我实现了一个数据库表,其中包含我所有的自定义用户属性,其中包含 Identity 字符串 userId 和 int 键。那行得通。

因此,我想在多个页面中获取 int userId。

在剃须刀页面中,我可以使用依赖注入来注入 UserManager userManager。我可以在需要 int userId 并使用 GetUserId 的每个剃刀页面上执行此操作,然后使用带有字符串 userId 的查询查找 int userId。但是,这意味着在我需要 userId 的每个 razor 页面上复制代码,因此这远非一个好的解决方案。我以为我会尝试实现一个静态类来做到这一点,但这似乎无法访问httpContext.Session,所以它不起作用(除非我错过了什么)。

更复杂的是,我认为我可以将 int userId 存储在 Session 中,但它会过期,所以每当我读取 Session 变量时,我都需要检查它是否为 null 并且是一个有效值,如果不是,则通过获取字符串 userId、找到 int userId 并将其保存到会话变量来刷新会话变量。同样,将该代码放在每个页面上并不好。

但是,如果我创建一个类来执行此操作,它没有 dbContext,并且我再次遇到一个问题,即如果它是一个静态类,它似乎无法访问 Session。

这感觉应该是一件很简单的事情,但我让自己陷入了一种螺旋式的“我到底该做什么”的状态。我尝试过做很多谷歌搜索,但似乎没有什么能解决问题

asp.net-core 会话变量 asp.net-core-identity

评论

0赞 Poul Bak 11/5/2023
我认为您应该查看“中间件”,这似乎是适合您的解决方案。中间件适用于所有请求,并且可以访问 HttpContext。只需搜索它。
0赞 user14554500 11/5/2023
我从来没有想过中间件。我已经为其他事情实现了中间件,所以了解它是如何工作的以及如何实现它。但是,我不确定中间件如何工作。您是否建议 1) 对于中间件,只是为了检查会话变量是否有效,如果不刷新它,则让页面读取会话变量本身,或者 2) 一个管理会话变量的中间件,并在对需要 int userId 的页面发出 GET 请求时读取它,然后中间件传递它(我不知道中间件如何将值传递给页面)
0赞 Poul Bak 11/5/2023
好吧,我最好为此做一个范围服务。然后,您可以将其注入到需要它的页面中(它也将针对所有请求运行)。
0赞 Jason Pan 11/6/2023
您可以尝试向 HttpContext 用户添加自定义声明。这是详细步骤userId
0赞 Dave B 11/6/2023
“所以有多个页面我想获取 int userId。”所有 Razor 页面都继承自 。设置“获取 int userid”的页面,以继承自自定义页面模型,该模型集中代码,在自定义/继承的页面模型中提供 DI,提供对 的访问等。从基页模型继承的 Razor 页可以访问自定义基页模型中定义的属性。PageModelHttpContext

答:

0赞 Dave B 11/9/2023 #1

因此,我想在多个页面中获取 int userId。

所有 Razor 页面都继承自类 。在方案中,将“获取 int userid”的 Razor 页面设置为从自定义页面模型继承,如本 SO 文章中所述。PageModel

从基本页面模型继承允许集中代码,否则这些代码将在每个单独的 Razor 页面模型中重复。

继承的类提供对以下内容的访问:DI 服务、 、 等。此外,从基页模型继承的 Razor 页可以访问自定义基页模型中定义的属性。HttpContextUser

下面的示例演示如何使用依赖项注入设置继承的基页模型。

示例注释

  • 此示例使用 DI 服务来替代需要访问数据库服务的方案。IConfiguration

  • 该属性在继承的基页模型中定义。请注意,该属性是在 Razor 视图页的方法中设置的,因为继承类中的方法使用该对象。此对象在继承类或 Razor 代码隐藏类的构造函数方法中不可用。 一旦代码执行到达该方法,它就可用。UserIdAsIntOnGet()GetUserIdAsInt()HttpContextHttpContextOnGet()

MyBasePageModel.cs

此 C# 类文件可以插入到项目中的任何位置。如果命名空间不是 .using.cshtml.cs[ProjectName].Pages

using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebApplication1.Pages
{
    public class MyBasePageModel : PageModel // Inherits from 'PageModel'
    {
        private readonly IConfiguration _configuration;

        public int UserIdAsInt { get; set; }

        public MyBasePageModel(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public int GetUserIdAsInt()
        {
            int? id = HttpContext.Session.GetInt32("UserIdAsInt");
            if (id == null)
            {
                // Get user ID as integer from database
                id = 100; // For sample purpose set 'id' variable to a hardcoded value
                HttpContext.Session.SetInt32("UserIdAsInt", (int)id);
                System.Diagnostics.Debug.WriteLine("User ID retrieved from database");
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("User ID retrieved from session");
            }
            return (int)id;
        }

        public string GetLoggingLevel()
        {
            return _configuration["Logging:LogLevel:Default"].ToString();
        }
    }
}

InheritFromBasePageModel.cshtml.cs

namespace WebApplication1.Pages
{
    public class InheritFromBasePageModelModel : MyBasePageModel // Inherits from the custom 'MyBasePageModel' class
    {
        public string? LoggingLevel { get; set; }

        public InheritFromBasePageModelModel(IConfiguration configuration)
                : base(configuration: configuration)
        {
        }

        public void OnGet()
        {
            UserIdAsInt = GetUserIdAsInt();
            LoggingLevel = GetLoggingLevel();
        }
    }
}

InheritFromBasePageModel.cshtml

@page
@model WebApplication1.Pages.InheritFromBasePageModelModel
@{
}
@section Styles {
    <style>
        p > span {
            font-weight: bold;
        }
    </style>
}
<p>Logging level property from base page model: <span>@Model.LoggingLevel</span></p>
<p>Integer value: <span>@Model.UserIdAsInt</span></p>

程序.cs

// Configure session state
// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-7.0#configure-session-state
// https://stackoverflow.com/questions/71070698/session-in-asp-net-core-mvc
// "add session middleware in your configuration file"
builder.Services.AddSession(options =>
{
    //options.IdleTimeout = TimeSpan.FromMinutes(1);   
});

app.UseSession();

(编辑 2023 年 11 月 11 日)

使用 OnPageHandlerExecutionAsync() 重写

上面的基页模型类要求从基页模型继承的每个 Razor 页在方法中添加行。MyBasePageModel.csUserIdAsInt = GetUserIdAsInt();OnGet()

这篇 SO 文章和文章演示如何为从基页模型继承的每个处理程序执行方法,而无需将其添加到每个 Razor 页面。OnGet()

下面是实现重写方法的修改后的类文件。MyBasePageModel.csOnPageHandlerExecutionAsync()

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace WebApplication1.Pages
{
    public class MyBasePageModel : PageModel
    {
        private readonly IConfiguration _configuration;

        public int UserIdAsInt { get; set; }

        public MyBasePageModel(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        // https://stackoverflow.com/questions/55030251/razor-pages-call-method-from-base-class-after-all-onget-handlers
        // https://www.learnrazorpages.com/razor-pages/filters
        // "Model binding completed. Handler has not been executed."
        public async override Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
        {
            if (context.HandlerMethod?.MethodInfo.Name == "OnGet")
            {
                // Code placed here will execute just before the OnGet()
                // method is executed.
                UserIdAsInt = await GetUserIdAsInt();
            }
            await base.OnPageHandlerExecutionAsync(context, next);
        }

        public async Task<int> GetUserIdAsInt()
        {
            int? id = HttpContext.Session.GetInt32("UserIdAsInt");

            // A valid user ID integer value exists in the 'Session'
            // object. Therefore, return this value.
            if (id != null)
            {
                System.Diagnostics.Debug.WriteLine("User ID retrieved from session");
                return (int)id;
            }

            // Get user ID as integer from database

            // 'Task.Run()' is used to simulate an async execution
            // of a database task.
            return await Task.Run(() =>
            {
                id = 200; // For sample purpose set 'id' variable to a hardcoded value
                HttpContext.Session.SetInt32("UserIdAsInt", (int)id);
                System.Diagnostics.Debug.WriteLine("User ID retrieved from database");
                return (int)id;
            });
        }

        public string? GetLoggingLevel()
        {
            if (_configuration == null) { return "(Configuration does not exist.)"; }
            return _configuration["Logging:LogLevel:Default"]?.ToString() ?? "Unset";
        }
    }
}