概要
ASP.NET Core のセッション情報を Redis に格納する方法を調べてみました。
開発環境は、macOS Mojave と .NET Core 2.2 SDK(v2.2.100-preview2)、Visual Studio Code になります。
まずは、Mac 単体で動作確認後、AWS(Amazon Web Services)の EC2 の Web サーバー2台 + ロードバランサー(L4スイッチ) + ElastiCache(Redis)で動作確認をします。
Redis を Mac にインストール
まず、Redis を Mac にインストールします。
Windows でも Chocolatey をインストールすることで Redis の動作を確認できるようです。
$ brew install redis
Redis を起動します。
$ brew services start redis
ASP.NET Core プロジェクトの作成
ASP.NET Core MVC プロジェクトを RedisTest という名前で作成します。
$ dotnet new mvc -o RedisTest
Redis に必要なパッケージを Nuget からインストールします。
$ cd RedisTest $ dotnet add package Microsoft.Extensions.Caching.Redis --version 2.2.0-preview2-35157 $ dotnet add package Microsoft.AspNetCore.DataProtection.Redis --version 2.2.0-preview2-35157 $ dotnet add package Microsoft.AspNetCore.Session --version 2.2.0-preview2-35157 $ dotnet restore
ASP.NET Core プロジェクトの修正
できあがったひな形を Redis が動作するように修正します。
Program.cs
を以下のように修正します。
//追加 using System.Net; //(中略) public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseKestrel(options => { options.Listen(IPAddress.Loopback, 5001); }) .UseUrls("http://*:5001/") .UseStartup<Startup>();
appsettings.Development.json
に Redis の設定を行います。
{ "ConnectionStrings": { "Redis": "localhost" }, "Logging": { "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Information" } } }
Startup.cs
を以下のように修正します。
services.AddSession()
, services.AddDistributedRedisCache
, app.UseSession()
が追加になっています。また、SetApplicationName
でアプリケーション名を指定します。これを指定しないと Web サーバー間でセッションが共有できないためご注意ください。
//追加 using Microsoft.AspNetCore.DataProtection; using StackExchange.Redis; //(中略) public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); //追加 services.AddSession(); //追加 services.AddDistributedRedisCache(o => { o.Configuration = Configuration.GetConnectionString("Redis"); }); //セッションを共有するための設定 var redis = ConnectionMultiplexer.Connect(Configuration.GetConnectionString("Redis")); services.AddDataProtection() .SetApplicationName("AppName") //重要!! .PersistKeysToRedis(redis, "DataProtection-Keys"); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); //app.UseHsts(); } //app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCookiePolicy(); //セッションを有効にする app.UseSession(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
HomeController.cs
の About メソッドを以下のように修正し、Redis にセッションデータを格納/取得するようにします。
public async Task<IActionResult> About() { //セッション情報をRedisからロードする await HttpContext.Session.LoadAsync(); //セッションから値を取得する string storedValue = HttpContext.Session.GetString("TestValue"); if (storedValue == null) { //データが存在しない場合はデータをセットする storedValue = "Testing session in Redis. Time of storage: " + DateTime.Now.ToString("s"); HttpContext.Session.SetString("TestValue", storedValue); //Redisにデータを格納する await HttpContext.Session.CommitAsync(); } ViewData["Message"] = "Value in session: " + storedValue; return View(); }
About.cshtml
は以下のようになっています。
@{ ViewData["Title"] = "About"; } <h2>@ViewData["Title"]</h2> <h3>@ViewData["Message"]</h3>
Mac 単体で動作確認
準備ができたので、ビルド&実行し、http://127.0.0.1:5001
にブラウザでアクセスします。
$ dotnet build $ dotnet run
問題なく表示できました。
AWS で動作確認
では、AWS で実際に2台の Web サーバー間で Redis を使ってセッションが共有されるか動作確認をします。
Web サーバーは CentOS 7 を使用し、nginx と.NET Core SDK をセットアップします。
nginx と ASP.NET Core の Web サーバーである Kestrel は、5001番ポートを介してリバースプロキシで HTTP サービスを提供するようにします。
ロードバランサーは Network Load Balancer(L4スイッチ)で作成し、ElastiCache で Redis を使用します。
これらのセットアップは、これだけで記事になるため詳細は割愛しますが、興味ある方は調べてみてください。
AWS へデプロイするために以下の修正を行います。
appsettings.json
に Redisのエンドポイントを設定します。
{ "ConnectionStrings": { "Redis": "Redisのエンドポイント(ポート番号なし)" }, "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*" }
Web サーバー1号機と2号機の区別が付くようにAbout.cshtml
を修正します。
- 1号機
@{ ViewData["Title"] = "About"; } <h1>Web Server 1</h1> <h2>@ViewData["Title"]</h2> <h3>@ViewData["Message"]</h3>
- 2号機
@{ ViewData["Title"] = "About"; } <h1>Web Server 2</h1> <h2>@ViewData["Title"]</h2> <h3>@ViewData["Message"]</h3>
準備ができたらロードバランサーへアクセスを行います。
最初は、Web サーバー1号機が表示されました。
しばらくすると、Web サーバー2号機が表示されましたが、同じ時刻を表示していますね。
これで問題なく、Redis で複数の Web サーバー間のセッションが共有されていることが確認できました。