有没有办法像在 Web 表单中一样对 asp.net 核心中的对象使用会话?
Is there a way to use session for objects in asp.net core like in web forms?
我有一个 Web 表单项目,我正在尝试将其转换为 asp.net 核心。我的问题是,在 Web 表单中,我将一个对象保存到会话中,当我得到它时,我可以对其进行更改并保留它们。另一方面,在核心中,我通过序列化将对象设置为会话。当我得到它并进行更改时,它不会影响存储在会话中的对象。有没有办法按原样保存对象(不序列化它),所以当我从会话中获取它并对其进行更改时,继续使用它而不必再次在会话中设置它?
会话是
System.Web.HttpContext.Current.Session["object"]
并做到了
AppHttpContext.Current.Session.GetString("object")
然后我将它反序列化为我想要的对象。
Ps:我使用 AppHttpContext 在控制器之外获取会话
ASP.NET 核心不支持直接将对象保存到 Session
中,Web 窗体项目可以采用这种方式。在 ASP.NET Core 中,仅直接支持将基本类型保存到 Session
中,例如 string
、int
或 byte
数组。因此,任何更复杂的对象都需要序列化为字符串或直接序列化为字节数组,然后可以将序列化存储在 Session
.
中
人们通常通过对对象进行 JSON 序列化以生成字符串,然后将字符串保存到 Session
中来实现这一点。但是,当您从 Session
检索 JSON 字符串并将其反序列化回对象时,对该对象的任何更改都不会反映在表示当前对象的先前 JSON 中存储在会话中。所以对对象的修改并没有直接体现在Session
.
这与在 Web 窗体中看到的行为有很大不同,这是因为对象没有存储在会话中,它的序列化是。因此,如果您更改对象并希望将这些更改存储在会话中,则需要再次序列化对象并将该序列化(例如json)存储在会话中。
有帮助吗?
从技术上讲,ASP.NET 也从不支持这一点。由于在这种情况下会话存储的工作方式,使用 InProc(即内存中)会话时恰好起作用是侥幸。如果您使用备用会话存储,如 SQL 服务器,您还必须 serialize/deserialize 对象进出会话。 ASP.NET Core 的不同之处仅在于它使用通用会话存储,因此它强制任何对象成为 serialized/deserialized,即使您使用的是内存存储。
就是说,您的问题是您根本没有将更改保存回来。同样,您依赖于偶然行为。因为 ASP.NET 直接将对象持久化在内存中,自动对该对象执行操作 "persisted" 因为它是同一个引用。反序列化时,您正在创建一个新实例,因此除非您之后将对象序列化回会话,否则操作将不会持续存在。
最后,无论是否使用 Web 表单,这都是从来没有推荐的甚至是正确的做事方式。会话存储是易变的。除了短期(和不可靠的)持久性之外,它不用于任何其他目的。换句话说,您永远不能指望会话中存在某些内容,因此您应该始终围绕数据不存在的情况进行防御性编码。如果你依赖于存在的东西,就像这里的情况一样,那么你总是在为失败做好准备。
但是,如果您正在执行类似多步骤表单的操作,则可以将各个步骤加入会话,但您应该实际上使用TempData
而不是 Session
。不过,在最后一步,您的组合对象应该保存在 SQL 服务器之类的东西中,而不是会话中。在几乎所有其他情况下,您应该简单地坚持使用 SQL 服务器之类的东西,并完全避免 Session
。
迁移任务不会很简单。
您可以按照以下步骤操作:
首先将您对 Session 的依赖替换为某种可以注入控制器或其他服务的服务。一个好主意是对该服务中的值进行硬编码,以检查是否所有依赖于早期会话实现的代码都能够使用新服务。
实现一个过滤器(例如通过在 Razor 页面的情况下实现 IAsyncPageFilter)来接入 HttpContext 用户并设置某种可以从缓存实现中检索的查找对象 - 一个好主意将是使用 Redis 分布式缓存。这个对象应该有 Key 作为用户身份 - 值可以是您可能想要添加到“会话”的任何数据。使用“缓存”服务来实现这一点,从客户端代码中隐藏缓存实现细节。 (请记住创建这些“请求”范围依赖项,以便正确填充 HttpContext 用户。)
在新服务上实施方法以添加/修改缓存对象以保持您的“会话”数据更新。
故事的寓意:减少对平台特定功能的依赖。至少使用某种服务封装这些依赖项,以后无需客户端代码即可根据这些功能替换这些服务。
要在会话中使用 object/array,您需要进行一些自定义:`
public static class SessionExtensions {
public static void SetObject(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetObject<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
} }
现在可以这样设置了:
var objComplex = new ComplexClass();
HttpContext.Session.SetObject("ComplexObject", objNew);
并检索它:
var objComplex = HttpContext.Session.GetObject("ComplexObject");
我有一个 Web 表单项目,我正在尝试将其转换为 asp.net 核心。我的问题是,在 Web 表单中,我将一个对象保存到会话中,当我得到它时,我可以对其进行更改并保留它们。另一方面,在核心中,我通过序列化将对象设置为会话。当我得到它并进行更改时,它不会影响存储在会话中的对象。有没有办法按原样保存对象(不序列化它),所以当我从会话中获取它并对其进行更改时,继续使用它而不必再次在会话中设置它?
会话是
System.Web.HttpContext.Current.Session["object"]
并做到了
AppHttpContext.Current.Session.GetString("object")
然后我将它反序列化为我想要的对象。
Ps:我使用 AppHttpContext 在控制器之外获取会话
ASP.NET 核心不支持直接将对象保存到 Session
中,Web 窗体项目可以采用这种方式。在 ASP.NET Core 中,仅直接支持将基本类型保存到 Session
中,例如 string
、int
或 byte
数组。因此,任何更复杂的对象都需要序列化为字符串或直接序列化为字节数组,然后可以将序列化存储在 Session
.
人们通常通过对对象进行 JSON 序列化以生成字符串,然后将字符串保存到 Session
中来实现这一点。但是,当您从 Session
检索 JSON 字符串并将其反序列化回对象时,对该对象的任何更改都不会反映在表示当前对象的先前 JSON 中存储在会话中。所以对对象的修改并没有直接体现在Session
.
这与在 Web 窗体中看到的行为有很大不同,这是因为对象没有存储在会话中,它的序列化是。因此,如果您更改对象并希望将这些更改存储在会话中,则需要再次序列化对象并将该序列化(例如json)存储在会话中。
有帮助吗?
从技术上讲,ASP.NET 也从不支持这一点。由于在这种情况下会话存储的工作方式,使用 InProc(即内存中)会话时恰好起作用是侥幸。如果您使用备用会话存储,如 SQL 服务器,您还必须 serialize/deserialize 对象进出会话。 ASP.NET Core 的不同之处仅在于它使用通用会话存储,因此它强制任何对象成为 serialized/deserialized,即使您使用的是内存存储。
就是说,您的问题是您根本没有将更改保存回来。同样,您依赖于偶然行为。因为 ASP.NET 直接将对象持久化在内存中,自动对该对象执行操作 "persisted" 因为它是同一个引用。反序列化时,您正在创建一个新实例,因此除非您之后将对象序列化回会话,否则操作将不会持续存在。
最后,无论是否使用 Web 表单,这都是从来没有推荐的甚至是正确的做事方式。会话存储是易变的。除了短期(和不可靠的)持久性之外,它不用于任何其他目的。换句话说,您永远不能指望会话中存在某些内容,因此您应该始终围绕数据不存在的情况进行防御性编码。如果你依赖于存在的东西,就像这里的情况一样,那么你总是在为失败做好准备。
但是,如果您正在执行类似多步骤表单的操作,则可以将各个步骤加入会话,但您应该实际上使用TempData
而不是 Session
。不过,在最后一步,您的组合对象应该保存在 SQL 服务器之类的东西中,而不是会话中。在几乎所有其他情况下,您应该简单地坚持使用 SQL 服务器之类的东西,并完全避免 Session
。
迁移任务不会很简单。
您可以按照以下步骤操作:
首先将您对 Session 的依赖替换为某种可以注入控制器或其他服务的服务。一个好主意是对该服务中的值进行硬编码,以检查是否所有依赖于早期会话实现的代码都能够使用新服务。
实现一个过滤器(例如通过在 Razor 页面的情况下实现 IAsyncPageFilter)来接入 HttpContext 用户并设置某种可以从缓存实现中检索的查找对象 - 一个好主意将是使用 Redis 分布式缓存。这个对象应该有 Key 作为用户身份 - 值可以是您可能想要添加到“会话”的任何数据。使用“缓存”服务来实现这一点,从客户端代码中隐藏缓存实现细节。 (请记住创建这些“请求”范围依赖项,以便正确填充 HttpContext 用户。)
在新服务上实施方法以添加/修改缓存对象以保持您的“会话”数据更新。
故事的寓意:减少对平台特定功能的依赖。至少使用某种服务封装这些依赖项,以后无需客户端代码即可根据这些功能替换这些服务。
要在会话中使用 object/array,您需要进行一些自定义:`
public static class SessionExtensions {
public static void SetObject(this ISession session, string key, object value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T GetObject<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
} }
现在可以这样设置了:
var objComplex = new ComplexClass();
HttpContext.Session.SetObject("ComplexObject", objNew);
并检索它:
var objComplex = HttpContext.Session.GetObject("ComplexObject");