Singleton Services中如何维护请求会话

时间:2019-02-08 10:17:33

标签: c# .net microservices azure-service-fabric

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

services.AddSingleton()

1 个答案:

答案 0 :(得分:0)

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

会话状态表现出以下行为:

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

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

-使用粘性会话将每个会话绑定到单个服务器上的特定应用程序实例。默认情况下,Azure App Service使用应用程序请求路由(ARR)强制执行粘性会话。但是,粘性会话可能会影响可伸缩性并使Web应用程序更新复杂化。更好的方法是使用Redis或SQL Server分布式缓存,它不需要粘性会话。有关更多信息,请参见Distributed caching in ASP.NET Core

-会话cookie通过IDataProtector加密。必须将Data Protection正确配置为读取每台计算机上的会话cookie。有关更多信息,请参见ASP.NET Core数据保护和密钥存储提供程序。

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

  • 任何IDistributedCache内存高速缓存。 IDistributedCache实现用作会话的后备存储。有关更多信息,请参见Distributed caching in 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环境中的字母并非总是那么容易创建和使用。

在Web应用程序中,我们可能正在考虑三种单例的使用:

  1. 每个网络请求的单个实例
  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;
            }
        }
    }
}

当我们在应用程序池中使用一个工作进程时,这将很好地工作,但是如今,当前大多数服务器平台确实具有多核处理器,而通过一个工作进程,我们将无法真正获得最大的收益。它。

File Logger类是一个Singleton的示例,可能涉及多个工作进程,即每个请求会将一些数据写入同一文件时。我们可以想象如果两个“单子”尝试同时写入同一文件会发生什么情况。

要解决此问题,我们必须在工作线程之间进行通信,以便所有工作线程都将访问仅存在于其中一个线程中的单例。

希望有帮助。