如何在Singleton Services中维护请求会话



我在启动文件中配置我的服务,如下所示。将对DocClient进行多次调用以获得响应。作为它的单例,服务器中会有一个共享对象。它如何确保和维护所有请求的会话。

services.AddSingleton()

ASP.NET Core通过向客户端提供包含会话ID的cookie来维护会话状态,会话ID随每个请求一起发送到应用程序。应用程序使用会话ID来获取会话数据。

会话状态显示以下行为:

由于会话cookie是特定于浏览器的,因此不会在浏览器之间共享会话。浏览器会话结束时会删除会话cookie。如果收到过期会话的cookie,则会创建一个使用相同会话cookie的新会话。空会话不会被保留——会话中必须至少设置一个值,才能在请求之间保持会话。如果没有保留会话,则会为每个新请求生成一个新的会话ID。在最后一次请求后,应用程序会在有限的时间内保留会话。该应用程序要么设置会话超时,要么使用默认值20分钟。会话状态非常适合存储特定会话的用户数据,但这些数据不需要跨会话永久存储。调用ISession.Clear实现时或会话过期时,会话数据将被删除。没有默认机制来通知应用程序代码客户端浏览器已关闭,或者客户端上的会话cookie已删除或过期。

内存缓存提供程序将会话数据存储在应用程序所在服务器的内存中。在服务器场场景中:

-使用粘性会话将每个会话绑定到单个服务器上的特定应用程序实例。默认情况下,Azure应用程序服务使用应用程序请求路由(ARR)来强制执行粘性会话。然而,粘性会话可能会影响可扩展性,并使web应用程序更新复杂化。更好的方法是使用Redis或SQL Server分布式缓存,这不需要粘性会话。有关详细信息,请参阅ASP.NET Core中的分布式缓存。

-会话cookie通过IDataProtector进行加密。必须正确配置数据保护以读取每台机器上的会话cookie。有关详细信息,请参阅ASP.NET核心数据保护和密钥存储提供程序。

配置会话状态Microsoft.AspNetCore.App元包中包含的Microsoft.AspNetCore.session包提供用于管理会话状态的中间件。要启用会话中间件,启动必须包含:

  • 任何IDistributedCache内存缓存。IDistributedCache实现用作会话的后备存储。有关详细信息,请参阅ASP.NET Core中的分布式缓存
  • 对ConfigureServices中AddSession的调用
  • 调用Configure中的UseSession

以下代码显示如何使用IDistributedCache:的默认内存内实现来设置内存内会话提供程序

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSession();
app.UseHttpContextItemsMiddleware();
app.UseMvc();
}
}

根据要求更新答案


网络环境中的单体并不总是那么容易创建和使用。

在web应用程序中,我们可能会考虑使用三种单一项:

  1. 每个web请求一个实例
  2. 每个用户单个实例(会话)
  3. 每个web应用程序的单个实例(最常用)

前两种情况并不是真正的问题;我真正感兴趣的是第三点,即"每个web应用程序的单个实例",这有时可能有点棘手。

通常,标准的Singleton模式会应用,因为默认情况下只有一个工作者。在我的几个项目中,我曾多次遇到一个问题——如何在多工作线程环境中实现Singleton。如果我们只有一个工作线程,那么实现Singleton并不是一个真正的问题,因为所有的web请求都将在整个工作线程中共享它的静态实例;唯一的问题是如何保护它,因为它仍然是一个多线程环境,这可以通过添加一个"锁"来简单地防止,如下例所示。

public class Singleton {
static Singleton instance = null;
static readonly object padlock = new object();
Singleton() { }
public static Singleton Instance {
get {
lock (padlock) {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
}
}

当我们在应用程序池中使用一个工作进程时,这将很好地工作,但现在,大多数当前的服务器平台都有多核处理器,而只有一个工作过程,我们不会真正充分利用它

Singleton的一个例子是File Logger类,其中多个工作进程可能是一个问题——当每个请求都将一些数据写入同一个文件时。我们可以想象,如果两个"单身汉"试图同时写入同一个文件,会发生什么。

为了解决这个问题,我们必须在工作线程之间进行通信,这样所有的工作线程都将访问一个只存在于其中一个线程中的singleton。

希望能有所帮助。

最新更新