Merge remote-tracking branch 'Session/rybrande/release21ToSrc' into rybrande/Mondo2.1
This commit is contained in:
commit
e6b3a5b79b
|
|
@ -0,0 +1,33 @@
|
|||
[Oo]bj/
|
||||
[Bb]in/
|
||||
TestResults/
|
||||
.nuget/
|
||||
*.sln.ide/
|
||||
_ReSharper.*/
|
||||
packages/
|
||||
artifacts/
|
||||
PublishProfiles/
|
||||
*.user
|
||||
*.suo
|
||||
*.cache
|
||||
*.docstates
|
||||
_ReSharper.*
|
||||
nuget.exe
|
||||
*net45.csproj
|
||||
*net451.csproj
|
||||
*k10.csproj
|
||||
*.psess
|
||||
*.vsp
|
||||
*.pidb
|
||||
*.userprefs
|
||||
*DS_Store
|
||||
*.ncrunchsolution
|
||||
*.*sdf
|
||||
*.ipch
|
||||
.vs/
|
||||
.vscode/
|
||||
project.lock.json
|
||||
.build/
|
||||
.testPublish/
|
||||
launchSettings.json
|
||||
global.json
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<Project>
|
||||
<Import
|
||||
Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))\AspNetCoreSettings.props"
|
||||
Condition=" '$(CI)' != 'true' AND '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))' != '' " />
|
||||
|
||||
<Import Project="version.props" />
|
||||
<Import Project="build\dependencies.props" />
|
||||
<Import Project="build\sources.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<Product>Microsoft ASP.NET Core</Product>
|
||||
<RepositoryUrl>https://github.com/aspnet/Session</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)build\Key.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
|
||||
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
|
||||
<NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"Default": {
|
||||
"rules": [
|
||||
"DefaultCompositeRule"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
Session
|
||||
================
|
||||
|
||||
AppVeyor: [](https://ci.appveyor.com/project/aspnetci/Session/branch/dev)
|
||||
|
||||
Travis: [](https://travis-ci.org/aspnet/Session)
|
||||
|
||||
Contains libraries for session state middleware for ASP.NET Core.
|
||||
|
||||
For ASP.NET 4.x session state, please go to https://github.com/aspnet/AspNetSessionState.
|
||||
|
||||
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26621.2
|
||||
MinimumVisualStudioVersion = 15.0.26730.03
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E9D63F97-6078-42AD-BFD3-F956BF921BB5}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
test\Directory.Build.props = test\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A189F10C-3A9C-4F81-83D0-32E5FE50DAD8}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\Directory.Build.props = src\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Session", "src\Microsoft.AspNetCore.Session\Microsoft.AspNetCore.Session.csproj", "{71802736-F640-4733-9671-02D267EDD76A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Session.Tests", "test\Microsoft.AspNetCore.Session.Tests\Microsoft.AspNetCore.Session.Tests.csproj", "{8C131A0A-BC1A-4CF3-8B77-8813FBFE5639}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{94E80ED2-9F27-40AC-A9EF-C707BDFAA3BE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SessionSample", "samples\SessionSample\SessionSample.csproj", "{FE0B9969-3BDE-4A7D-BE1B-47EAE8DBF365}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{3B45F658-5BF1-4E07-BE9C-6F5110AC2277}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.appveyor.yml = .appveyor.yml
|
||||
.gitattributes = .gitattributes
|
||||
.gitignore = .gitignore
|
||||
.travis.yml = .travis.yml
|
||||
Directory.Build.props = Directory.Build.props
|
||||
Directory.Build.targets = Directory.Build.targets
|
||||
NuGet.config = NuGet.config
|
||||
NuGetPackageVerifier.json = NuGetPackageVerifier.json
|
||||
README.md = README.md
|
||||
version.xml = version.xml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{4F21221F-2813-41B7-AAFC-E03FD52971CC}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
build\common.props = build\common.props
|
||||
build\dependencies.props = build\dependencies.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{71802736-F640-4733-9671-02D267EDD76A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{71802736-F640-4733-9671-02D267EDD76A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{71802736-F640-4733-9671-02D267EDD76A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{71802736-F640-4733-9671-02D267EDD76A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8C131A0A-BC1A-4CF3-8B77-8813FBFE5639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8C131A0A-BC1A-4CF3-8B77-8813FBFE5639}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8C131A0A-BC1A-4CF3-8B77-8813FBFE5639}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8C131A0A-BC1A-4CF3-8B77-8813FBFE5639}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FE0B9969-3BDE-4A7D-BE1B-47EAE8DBF365}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FE0B9969-3BDE-4A7D-BE1B-47EAE8DBF365}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FE0B9969-3BDE-4A7D-BE1B-47EAE8DBF365}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FE0B9969-3BDE-4A7D-BE1B-47EAE8DBF365}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{71802736-F640-4733-9671-02D267EDD76A} = {A189F10C-3A9C-4F81-83D0-32E5FE50DAD8}
|
||||
{8C131A0A-BC1A-4CF3-8B77-8813FBFE5639} = {E9D63F97-6078-42AD-BFD3-F956BF921BB5}
|
||||
{FE0B9969-3BDE-4A7D-BE1B-47EAE8DBF365} = {94E80ED2-9F27-40AC-A9EF-C707BDFAA3BE}
|
||||
{4F21221F-2813-41B7-AAFC-E03FD52971CC} = {3B45F658-5BF1-4E07-BE9C-6F5110AC2277}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6AE224B9-B604-4E47-9617-9D114DAE9BE5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Binary file not shown.
|
|
@ -0,0 +1,36 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- These package versions may be overridden or updated by automation. -->
|
||||
<PropertyGroup Label="Package Versions: Auto">
|
||||
<InternalAspNetCoreSdkPackageVersion>2.1.3-rtm-15802</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
|
||||
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
|
||||
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
|
||||
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
|
||||
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
||||
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- This may import a generated file which may override the variables above. -->
|
||||
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
|
||||
|
||||
<!-- These are package versions that should not be overridden or updated by automation. -->
|
||||
<PropertyGroup Label="Package Versions: Pinned">
|
||||
<MicrosoftAspNetCoreDataProtectionPackageVersion>2.1.1</MicrosoftAspNetCoreDataProtectionPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreHttpAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.1</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
|
||||
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelPackageVersion>
|
||||
<MicrosoftAspNetCoreTestHostPackageVersion>2.1.1</MicrosoftAspNetCoreTestHostPackageVersion>
|
||||
<MicrosoftExtensionsCachingAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsCachingAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsCachingMemoryPackageVersion>2.1.1</MicrosoftExtensionsCachingMemoryPackageVersion>
|
||||
<MicrosoftExtensionsCachingRedisPackageVersion>2.1.1</MicrosoftExtensionsCachingRedisPackageVersion>
|
||||
<MicrosoftExtensionsCachingSqlServerPackageVersion>2.1.1</MicrosoftExtensionsCachingSqlServerPackageVersion>
|
||||
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.1</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.1</MicrosoftExtensionsLoggingTestingPackageVersion>
|
||||
<MicrosoftExtensionsOptionsPackageVersion>2.1.1</MicrosoftExtensionsOptionsPackageVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<Project>
|
||||
<Import Project="dependencies.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- These properties are use by the automation that updates dependencies.props -->
|
||||
<LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
|
||||
<LineupPackageVersion>2.1.0-rc1-*</LineupPackageVersion>
|
||||
<LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp20PackageVersion)" />
|
||||
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<Project>
|
||||
<Import Project="$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''"/>
|
||||
|
||||
<PropertyGroup Label="RestoreSources">
|
||||
<RestoreSources>$(DotNetRestoreSources)</RestoreSources>
|
||||
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true' AND '$(AspNetUniverseBuildOffline)' != 'true' ">
|
||||
$(RestoreSources);
|
||||
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
|
||||
https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
|
||||
</RestoreSources>
|
||||
<RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
|
||||
$(RestoreSources);
|
||||
https://api.nuget.org/v3/index.json;
|
||||
</RestoreSources>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:2481/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"SessionSample": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Session\Microsoft.AspNetCore.Session.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="$(MicrosoftExtensionsCachingRedisPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="$(MicrosoftExtensionsCachingSqlServerPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace SessionSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Adds a default in-memory implementation of IDistributedCache
|
||||
services.AddDistributedMemoryCache();
|
||||
|
||||
// Uncomment the following line to use the Microsoft SQL Server implementation of IDistributedCache.
|
||||
// Note that this would require setting up the session state database.
|
||||
//services.AddSqlServerCache(o =>
|
||||
//{
|
||||
// o.ConnectionString = "Server=.;Database=ASPNET5SessionState;Trusted_Connection=True;";
|
||||
// o.SchemaName = "dbo";
|
||||
// o.TableName = "Sessions";
|
||||
//});
|
||||
|
||||
// Uncomment the following line to use the Redis implementation of IDistributedCache.
|
||||
// This will override any previously registered IDistributedCache service.
|
||||
//services.AddDistributedRedisCache(o =>
|
||||
//{
|
||||
// o.Configuration = "localhost";
|
||||
// o.InstanceName = "SampleInstance";
|
||||
//});
|
||||
|
||||
services.AddSession(o =>
|
||||
{
|
||||
o.IdleTimeout = TimeSpan.FromSeconds(10);
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseSession();
|
||||
|
||||
app.Map("/session", subApp =>
|
||||
{
|
||||
subApp.Run(async context =>
|
||||
{
|
||||
int visits = 0;
|
||||
visits = context.Session.GetInt32("visits") ?? 0;
|
||||
context.Session.SetInt32("visits", ++visits);
|
||||
await context.Response.WriteAsync("Counting: You have visited our page this many times: " + visits);
|
||||
});
|
||||
});
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
int visits = 0;
|
||||
visits = context.Session.GetInt32("visits") ?? 0;
|
||||
await context.Response.WriteAsync("<html><body>");
|
||||
if (visits == 0)
|
||||
{
|
||||
await context.Response.WriteAsync("Your session has not been established.<br>");
|
||||
await context.Response.WriteAsync(DateTime.Now + "<br>");
|
||||
await context.Response.WriteAsync("<a href=\"/session\">Establish session</a>.<br>");
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Session.SetInt32("visits", ++visits);
|
||||
await context.Response.WriteAsync("Your session was located, you've visited the site this many times: " + visits);
|
||||
}
|
||||
await context.Response.WriteAsync("</body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.ConfigureLogging(factory => factory.AddConsole())
|
||||
.UseKestrel()
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<Project>
|
||||
<Import Project="..\Directory.Build.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
internal static class CookieProtection
|
||||
{
|
||||
internal static string Protect(IDataProtector protector, string data)
|
||||
{
|
||||
if (protector == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(protector));
|
||||
}
|
||||
if (string.IsNullOrEmpty(data))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
var userData = Encoding.UTF8.GetBytes(data);
|
||||
|
||||
var protectedData = protector.Protect(userData);
|
||||
return Convert.ToBase64String(protectedData).TrimEnd('=');
|
||||
}
|
||||
|
||||
internal static string Unprotect(IDataProtector protector, string protectedText, ILogger logger)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(protectedText))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var protectedData = Convert.FromBase64String(Pad(protectedText));
|
||||
if (protectedData == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var userData = protector.Unprotect(protectedData);
|
||||
if (userData == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return Encoding.UTF8.GetString(userData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log the exception, but do not leak other information
|
||||
logger.ErrorUnprotectingSessionCookie(ex);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private static string Pad(string text)
|
||||
{
|
||||
var padding = 3 - ((text.Length + 3) % 4);
|
||||
if (padding == 0)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
return text + new string('=', padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
public class DistributedSession : ISession
|
||||
{
|
||||
private static readonly RandomNumberGenerator CryptoRandom = RandomNumberGenerator.Create();
|
||||
private const int IdByteCount = 16;
|
||||
|
||||
private const byte SerializationRevision = 2;
|
||||
private const int KeyLengthLimit = ushort.MaxValue;
|
||||
|
||||
private readonly IDistributedCache _cache;
|
||||
private readonly string _sessionKey;
|
||||
private readonly TimeSpan _idleTimeout;
|
||||
private readonly TimeSpan _ioTimeout;
|
||||
private readonly Func<bool> _tryEstablishSession;
|
||||
private readonly ILogger _logger;
|
||||
private IDictionary<EncodedKey, byte[]> _store;
|
||||
private bool _isModified;
|
||||
private bool _loaded;
|
||||
private bool _isAvailable;
|
||||
private bool _isNewSessionKey;
|
||||
private string _sessionId;
|
||||
private byte[] _sessionIdBytes;
|
||||
|
||||
public DistributedSession(
|
||||
IDistributedCache cache,
|
||||
string sessionKey,
|
||||
TimeSpan idleTimeout,
|
||||
TimeSpan ioTimeout,
|
||||
Func<bool> tryEstablishSession,
|
||||
ILoggerFactory loggerFactory,
|
||||
bool isNewSessionKey)
|
||||
{
|
||||
if (cache == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(cache));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(sessionKey))
|
||||
{
|
||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(sessionKey));
|
||||
}
|
||||
|
||||
if (tryEstablishSession == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tryEstablishSession));
|
||||
}
|
||||
|
||||
if (loggerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_cache = cache;
|
||||
_sessionKey = sessionKey;
|
||||
_idleTimeout = idleTimeout;
|
||||
_ioTimeout = ioTimeout;
|
||||
_tryEstablishSession = tryEstablishSession;
|
||||
_store = new Dictionary<EncodedKey, byte[]>();
|
||||
_logger = loggerFactory.CreateLogger<DistributedSession>();
|
||||
_isNewSessionKey = isNewSessionKey;
|
||||
}
|
||||
|
||||
public bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
return _isAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
public string Id
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
if (_sessionId == null)
|
||||
{
|
||||
_sessionId = new Guid(IdBytes).ToString();
|
||||
}
|
||||
return _sessionId;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] IdBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsAvailable && _sessionIdBytes == null)
|
||||
{
|
||||
_sessionIdBytes = new byte[IdByteCount];
|
||||
CryptoRandom.GetBytes(_sessionIdBytes);
|
||||
}
|
||||
return _sessionIdBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
return _store.Keys.Select(key => key.KeyString);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out byte[] value)
|
||||
{
|
||||
Load();
|
||||
return _store.TryGetValue(new EncodedKey(key), out value);
|
||||
}
|
||||
|
||||
public void Set(string key, byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
if (IsAvailable)
|
||||
{
|
||||
var encodedKey = new EncodedKey(key);
|
||||
if (encodedKey.KeyBytes.Length > KeyLengthLimit)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(key),
|
||||
Resources.FormatException_KeyLengthIsExceeded(KeyLengthLimit));
|
||||
}
|
||||
|
||||
if (!_tryEstablishSession())
|
||||
{
|
||||
throw new InvalidOperationException(Resources.Exception_InvalidSessionEstablishment);
|
||||
}
|
||||
_isModified = true;
|
||||
byte[] copy = new byte[value.Length];
|
||||
Buffer.BlockCopy(src: value, srcOffset: 0, dst: copy, dstOffset: 0, count: value.Length);
|
||||
_store[encodedKey] = copy;
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
Load();
|
||||
_isModified |= _store.Remove(new EncodedKey(key));
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Load();
|
||||
_isModified |= _store.Count > 0;
|
||||
_store.Clear();
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
if (!_loaded)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = _cache.Get(_sessionKey);
|
||||
if (data != null)
|
||||
{
|
||||
Deserialize(new MemoryStream(data));
|
||||
}
|
||||
else if (!_isNewSessionKey)
|
||||
{
|
||||
_logger.AccessingExpiredSession(_sessionKey);
|
||||
}
|
||||
_isAvailable = true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.SessionCacheReadException(_sessionKey, exception);
|
||||
_isAvailable = false;
|
||||
_sessionId = string.Empty;
|
||||
_sessionIdBytes = null;
|
||||
_store = new NoOpSessionStore();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This will throw if called directly and a failure occurs. The user is expected to handle the failures.
|
||||
public async Task LoadAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!_loaded)
|
||||
{
|
||||
using (var timeout = new CancellationTokenSource(_ioTimeout))
|
||||
{
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, cancellationToken);
|
||||
try
|
||||
{
|
||||
cts.Token.ThrowIfCancellationRequested();
|
||||
var data = await _cache.GetAsync(_sessionKey, cts.Token);
|
||||
if (data != null)
|
||||
{
|
||||
Deserialize(new MemoryStream(data));
|
||||
}
|
||||
else if (!_isNewSessionKey)
|
||||
{
|
||||
_logger.AccessingExpiredSession(_sessionKey);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException oex)
|
||||
{
|
||||
if (timeout.Token.IsCancellationRequested)
|
||||
{
|
||||
_logger.SessionLoadingTimeout();
|
||||
throw new OperationCanceledException("Timed out loading the session.", oex, timeout.Token);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
_isAvailable = true;
|
||||
_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CommitAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (var timeout = new CancellationTokenSource(_ioTimeout))
|
||||
{
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, cancellationToken);
|
||||
if (_isModified)
|
||||
{
|
||||
if (_logger.IsEnabled(LogLevel.Information))
|
||||
{
|
||||
// This operation is only so we can log if the session already existed.
|
||||
// Log and ignore failures.
|
||||
try
|
||||
{
|
||||
cts.Token.ThrowIfCancellationRequested();
|
||||
var data = await _cache.GetAsync(_sessionKey, cts.Token);
|
||||
if (data == null)
|
||||
{
|
||||
_logger.SessionStarted(_sessionKey, Id);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.SessionCacheReadException(_sessionKey, exception);
|
||||
}
|
||||
}
|
||||
|
||||
var stream = new MemoryStream();
|
||||
Serialize(stream);
|
||||
|
||||
try
|
||||
{
|
||||
cts.Token.ThrowIfCancellationRequested();
|
||||
await _cache.SetAsync(
|
||||
_sessionKey,
|
||||
stream.ToArray(),
|
||||
new DistributedCacheEntryOptions().SetSlidingExpiration(_idleTimeout),
|
||||
cts.Token);
|
||||
_isModified = false;
|
||||
_logger.SessionStored(_sessionKey, Id, _store.Count);
|
||||
}
|
||||
catch (OperationCanceledException oex)
|
||||
{
|
||||
if (timeout.Token.IsCancellationRequested)
|
||||
{
|
||||
_logger.SessionCommitTimeout();
|
||||
throw new OperationCanceledException("Timed out committing the session.", oex, timeout.Token);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
await _cache.RefreshAsync(_sessionKey, cts.Token);
|
||||
}
|
||||
catch (OperationCanceledException oex)
|
||||
{
|
||||
if (timeout.Token.IsCancellationRequested)
|
||||
{
|
||||
_logger.SessionRefreshTimeout();
|
||||
throw new OperationCanceledException("Timed out refreshing the session.", oex, timeout.Token);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format:
|
||||
// Serialization revision: 1 byte, range 0-255
|
||||
// Entry count: 3 bytes, range 0-16,777,215
|
||||
// SessionId: IdByteCount bytes (16)
|
||||
// foreach entry:
|
||||
// key name byte length: 2 bytes, range 0-65,535
|
||||
// UTF-8 encoded key name byte[]
|
||||
// data byte length: 4 bytes, range 0-2,147,483,647
|
||||
// data byte[]
|
||||
private void Serialize(Stream output)
|
||||
{
|
||||
output.WriteByte(SerializationRevision);
|
||||
SerializeNumAs3Bytes(output, _store.Count);
|
||||
output.Write(IdBytes, 0, IdByteCount);
|
||||
|
||||
foreach (var entry in _store)
|
||||
{
|
||||
var keyBytes = entry.Key.KeyBytes;
|
||||
SerializeNumAs2Bytes(output, keyBytes.Length);
|
||||
output.Write(keyBytes, 0, keyBytes.Length);
|
||||
SerializeNumAs4Bytes(output, entry.Value.Length);
|
||||
output.Write(entry.Value, 0, entry.Value.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private void Deserialize(Stream content)
|
||||
{
|
||||
if (content == null || content.ReadByte() != SerializationRevision)
|
||||
{
|
||||
// Replace the un-readable format.
|
||||
_isModified = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int expectedEntries = DeserializeNumFrom3Bytes(content);
|
||||
_sessionIdBytes = ReadBytes(content, IdByteCount);
|
||||
|
||||
for (int i = 0; i < expectedEntries; i++)
|
||||
{
|
||||
int keyLength = DeserializeNumFrom2Bytes(content);
|
||||
var key = new EncodedKey(ReadBytes(content, keyLength));
|
||||
int dataLength = DeserializeNumFrom4Bytes(content);
|
||||
_store[key] = ReadBytes(content, dataLength);
|
||||
}
|
||||
|
||||
if (_logger.IsEnabled(LogLevel.Debug))
|
||||
{
|
||||
_sessionId = new Guid(_sessionIdBytes).ToString();
|
||||
_logger.SessionLoaded(_sessionKey, _sessionId, expectedEntries);
|
||||
}
|
||||
}
|
||||
|
||||
private void SerializeNumAs2Bytes(Stream output, int num)
|
||||
{
|
||||
if (num < 0 || ushort.MaxValue < num)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(num), Resources.Exception_InvalidToSerializeIn2Bytes);
|
||||
}
|
||||
output.WriteByte((byte)(num >> 8));
|
||||
output.WriteByte((byte)(0xFF & num));
|
||||
}
|
||||
|
||||
private int DeserializeNumFrom2Bytes(Stream content)
|
||||
{
|
||||
return content.ReadByte() << 8 | content.ReadByte();
|
||||
}
|
||||
|
||||
private void SerializeNumAs3Bytes(Stream output, int num)
|
||||
{
|
||||
if (num < 0 || 0xFFFFFF < num)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(num), Resources.Exception_InvalidToSerializeIn3Bytes);
|
||||
}
|
||||
output.WriteByte((byte)(num >> 16));
|
||||
output.WriteByte((byte)(0xFF & (num >> 8)));
|
||||
output.WriteByte((byte)(0xFF & num));
|
||||
}
|
||||
|
||||
private int DeserializeNumFrom3Bytes(Stream content)
|
||||
{
|
||||
return content.ReadByte() << 16 | content.ReadByte() << 8 | content.ReadByte();
|
||||
}
|
||||
|
||||
private void SerializeNumAs4Bytes(Stream output, int num)
|
||||
{
|
||||
if (num < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(num), Resources.Exception_NumberShouldNotBeNegative);
|
||||
}
|
||||
output.WriteByte((byte)(num >> 24));
|
||||
output.WriteByte((byte)(0xFF & (num >> 16)));
|
||||
output.WriteByte((byte)(0xFF & (num >> 8)));
|
||||
output.WriteByte((byte)(0xFF & num));
|
||||
}
|
||||
|
||||
private int DeserializeNumFrom4Bytes(Stream content)
|
||||
{
|
||||
return content.ReadByte() << 24 | content.ReadByte() << 16 | content.ReadByte() << 8 | content.ReadByte();
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(Stream stream, int count)
|
||||
{
|
||||
var output = new byte[count];
|
||||
int total = 0;
|
||||
while (total < count)
|
||||
{
|
||||
var read = stream.Read(output, total, count - total);
|
||||
if (read == 0)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
total += read;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
public class DistributedSessionStore : ISessionStore
|
||||
{
|
||||
private readonly IDistributedCache _cache;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
|
||||
public DistributedSessionStore(IDistributedCache cache, ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (cache == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(cache));
|
||||
}
|
||||
|
||||
if (loggerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_cache = cache;
|
||||
_loggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
public ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sessionKey))
|
||||
{
|
||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(sessionKey));
|
||||
}
|
||||
|
||||
if (tryEstablishSession == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tryEstablishSession));
|
||||
}
|
||||
|
||||
return new DistributedSession(_cache, sessionKey, idleTimeout, ioTimeout, tryEstablishSession, _loggerFactory, isNewSessionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
// Keys are stored in their utf-8 encoded state.
|
||||
// This saves us from de-serializing and re-serializing every key on every request.
|
||||
internal class EncodedKey
|
||||
{
|
||||
private string _keyString;
|
||||
private int? _hashCode;
|
||||
|
||||
internal EncodedKey(string key)
|
||||
{
|
||||
_keyString = key;
|
||||
KeyBytes = Encoding.UTF8.GetBytes(key);
|
||||
}
|
||||
|
||||
public EncodedKey(byte[] key)
|
||||
{
|
||||
KeyBytes = key;
|
||||
}
|
||||
|
||||
internal string KeyString
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_keyString == null)
|
||||
{
|
||||
_keyString = Encoding.UTF8.GetString(KeyBytes, 0, KeyBytes.Length);
|
||||
}
|
||||
return _keyString;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] KeyBytes { get; private set; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var otherKey = obj as EncodedKey;
|
||||
if (otherKey == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (KeyBytes.Length != otherKey.KeyBytes.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_hashCode.HasValue && otherKey._hashCode.HasValue
|
||||
&& _hashCode.Value != otherKey._hashCode.Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < KeyBytes.Length; i++)
|
||||
{
|
||||
if (KeyBytes[i] != otherKey.KeyBytes[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
if (!_hashCode.HasValue)
|
||||
{
|
||||
_hashCode = SipHash.GetHashCode(KeyBytes);
|
||||
}
|
||||
return _hashCode.Value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return KeyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
public interface ISessionStore
|
||||
{
|
||||
ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Extensions.Logging
|
||||
{
|
||||
internal static class LoggingExtensions
|
||||
{
|
||||
private static Action<ILogger, Exception> _errorClosingTheSession;
|
||||
private static Action<ILogger, string, Exception> _accessingExpiredSession;
|
||||
private static Action<ILogger, string, string, Exception> _sessionStarted;
|
||||
private static Action<ILogger, string, string, int, Exception> _sessionLoaded;
|
||||
private static Action<ILogger, string, string, int, Exception> _sessionStored;
|
||||
private static Action<ILogger, string, Exception> _sessionCacheReadException;
|
||||
private static Action<ILogger, Exception> _errorUnprotectingCookie;
|
||||
private static Action<ILogger, Exception> _sessionLoadingTimeout;
|
||||
private static Action<ILogger, Exception> _sessionCommitTimeout;
|
||||
private static Action<ILogger, Exception> _sessionCommitCanceled;
|
||||
private static Action<ILogger, Exception> _sessionRefreshTimeout;
|
||||
private static Action<ILogger, Exception> _sessionRefreshCanceled;
|
||||
|
||||
static LoggingExtensions()
|
||||
{
|
||||
_errorClosingTheSession = LoggerMessage.Define(
|
||||
eventId: 1,
|
||||
logLevel: LogLevel.Error,
|
||||
formatString: "Error closing the session.");
|
||||
_accessingExpiredSession = LoggerMessage.Define<string>(
|
||||
eventId: 2,
|
||||
logLevel: LogLevel.Information,
|
||||
formatString: "Accessing expired session, Key:{sessionKey}");
|
||||
_sessionStarted = LoggerMessage.Define<string, string>(
|
||||
eventId: 3,
|
||||
logLevel: LogLevel.Information,
|
||||
formatString: "Session started; Key:{sessionKey}, Id:{sessionId}");
|
||||
_sessionLoaded = LoggerMessage.Define<string, string, int>(
|
||||
eventId: 4,
|
||||
logLevel: LogLevel.Debug,
|
||||
formatString: "Session loaded; Key:{sessionKey}, Id:{sessionId}, Count:{count}");
|
||||
_sessionStored = LoggerMessage.Define<string, string, int>(
|
||||
eventId: 5,
|
||||
logLevel: LogLevel.Debug,
|
||||
formatString: "Session stored; Key:{sessionKey}, Id:{sessionId}, Count:{count}");
|
||||
_sessionCacheReadException = LoggerMessage.Define<string>(
|
||||
eventId: 6,
|
||||
logLevel: LogLevel.Error,
|
||||
formatString: "Session cache read exception, Key:{sessionKey}");
|
||||
_errorUnprotectingCookie = LoggerMessage.Define(
|
||||
eventId: 7,
|
||||
logLevel: LogLevel.Warning,
|
||||
formatString: "Error unprotecting the session cookie.");
|
||||
_sessionLoadingTimeout = LoggerMessage.Define(
|
||||
eventId: 8,
|
||||
logLevel: LogLevel.Warning,
|
||||
formatString: "Loading the session timed out.");
|
||||
_sessionCommitTimeout = LoggerMessage.Define(
|
||||
eventId: 9,
|
||||
logLevel: LogLevel.Warning,
|
||||
formatString: "Committing the session timed out.");
|
||||
_sessionCommitCanceled = LoggerMessage.Define(
|
||||
eventId: 10,
|
||||
logLevel: LogLevel.Information,
|
||||
formatString: "Committing the session was canceled.");
|
||||
_sessionRefreshTimeout = LoggerMessage.Define(
|
||||
eventId: 11,
|
||||
logLevel: LogLevel.Warning,
|
||||
formatString: "Refreshing the session timed out.");
|
||||
_sessionRefreshCanceled = LoggerMessage.Define(
|
||||
eventId: 12,
|
||||
logLevel: LogLevel.Information,
|
||||
formatString: "Refreshing the session was canceled.");
|
||||
}
|
||||
|
||||
public static void ErrorClosingTheSession(this ILogger logger, Exception exception)
|
||||
{
|
||||
_errorClosingTheSession(logger, exception);
|
||||
}
|
||||
|
||||
public static void AccessingExpiredSession(this ILogger logger, string sessionKey)
|
||||
{
|
||||
_accessingExpiredSession(logger, sessionKey, null);
|
||||
}
|
||||
|
||||
public static void SessionStarted(this ILogger logger, string sessionKey, string sessionId)
|
||||
{
|
||||
_sessionStarted(logger, sessionKey, sessionId, null);
|
||||
}
|
||||
|
||||
public static void SessionLoaded(this ILogger logger, string sessionKey, string sessionId, int count)
|
||||
{
|
||||
_sessionLoaded(logger, sessionKey, sessionId, count, null);
|
||||
}
|
||||
|
||||
public static void SessionStored(this ILogger logger, string sessionKey, string sessionId, int count)
|
||||
{
|
||||
_sessionStored(logger, sessionKey, sessionId, count, null);
|
||||
}
|
||||
|
||||
public static void SessionCacheReadException(this ILogger logger, string sessionKey, Exception exception)
|
||||
{
|
||||
_sessionCacheReadException(logger, sessionKey, exception);
|
||||
}
|
||||
|
||||
public static void ErrorUnprotectingSessionCookie(this ILogger logger, Exception exception)
|
||||
{
|
||||
_errorUnprotectingCookie(logger, exception);
|
||||
}
|
||||
|
||||
public static void SessionLoadingTimeout(this ILogger logger)
|
||||
{
|
||||
_sessionLoadingTimeout(logger, null);
|
||||
}
|
||||
|
||||
public static void SessionCommitTimeout(this ILogger logger)
|
||||
{
|
||||
_sessionCommitTimeout(logger, null);
|
||||
}
|
||||
|
||||
public static void SessionCommitCanceled(this ILogger logger)
|
||||
{
|
||||
_sessionCommitCanceled(logger, null);
|
||||
}
|
||||
|
||||
public static void SessionRefreshTimeout(this ILogger logger)
|
||||
{
|
||||
_sessionRefreshTimeout(logger, null);
|
||||
}
|
||||
|
||||
public static void SessionRefreshCanceled(this ILogger logger)
|
||||
{
|
||||
_sessionRefreshCanceled(logger, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>ASP.NET Core session state middleware.</Description>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageTags>aspnetcore;session;sessionstate</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(MicrosoftAspNetCoreDataProtectionPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(MicrosoftAspNetCoreHttpAbstractionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="$(MicrosoftExtensionsCachingAbstractionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
internal class NoOpSessionStore : IDictionary<EncodedKey, byte[]>
|
||||
{
|
||||
public byte[] this[EncodedKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public int Count { get; } = 0;
|
||||
|
||||
public bool IsReadOnly { get; } = false;
|
||||
|
||||
public ICollection<EncodedKey> Keys { get; } = new EncodedKey[0];
|
||||
|
||||
public ICollection<byte[]> Values { get; } = new byte[0][];
|
||||
|
||||
public void Add(KeyValuePair<EncodedKey, byte[]> item) { }
|
||||
|
||||
public void Add(EncodedKey key, byte[] value) { }
|
||||
|
||||
public void Clear() { }
|
||||
|
||||
public bool Contains(KeyValuePair<EncodedKey, byte[]> item) => false;
|
||||
|
||||
public bool ContainsKey(EncodedKey key) => false;
|
||||
|
||||
public void CopyTo(KeyValuePair<EncodedKey, byte[]>[] array, int arrayIndex) { }
|
||||
|
||||
public IEnumerator<KeyValuePair<EncodedKey, byte[]>> GetEnumerator() => Enumerable.Empty<KeyValuePair<EncodedKey, byte[]>>().GetEnumerator();
|
||||
|
||||
public bool Remove(KeyValuePair<EncodedKey, byte[]> item) => false;
|
||||
|
||||
public bool Remove(EncodedKey key) => false;
|
||||
|
||||
public bool TryGetValue(EncodedKey key, out byte[] value)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
||||
126
src/Session/src/Microsoft.AspNetCore.Session/Properties/Resources.Designer.cs
generated
Normal file
126
src/Session/src/Microsoft.AspNetCore.Session/Properties/Resources.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNetCore.Session.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The key cannot be longer than '{0}' when encoded with UTF-8.
|
||||
/// </summary>
|
||||
internal static string Exception_KeyLengthIsExceeded
|
||||
{
|
||||
get { return GetString("Exception_KeyLengthIsExceeded"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key cannot be longer than '{0}' when encoded with UTF-8.
|
||||
/// </summary>
|
||||
internal static string FormatException_KeyLengthIsExceeded(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("Exception_KeyLengthIsExceeded"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The session cannot be established after the response has started.
|
||||
/// </summary>
|
||||
internal static string Exception_InvalidSessionEstablishment
|
||||
{
|
||||
get { return GetString("Exception_InvalidSessionEstablishment"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The session cannot be established after the response has started.
|
||||
/// </summary>
|
||||
internal static string FormatException_InvalidSessionEstablishment()
|
||||
{
|
||||
return GetString("Exception_InvalidSessionEstablishment");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value cannot be serialized in two bytes.
|
||||
/// </summary>
|
||||
internal static string Exception_InvalidToSerializeIn2Bytes
|
||||
{
|
||||
get { return GetString("Exception_InvalidToSerializeIn2Bytes"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value cannot be serialized in two bytes.
|
||||
/// </summary>
|
||||
internal static string FormatException_InvalidToSerializeIn2Bytes()
|
||||
{
|
||||
return GetString("Exception_InvalidToSerializeIn2Bytes");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value cannot be serialized in three bytes.
|
||||
/// </summary>
|
||||
internal static string Exception_InvalidToSerializeIn3Bytes
|
||||
{
|
||||
get { return GetString("Exception_InvalidToSerializeIn3Bytes"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value cannot be serialized in three bytes.
|
||||
/// </summary>
|
||||
internal static string FormatException_InvalidToSerializeIn3Bytes()
|
||||
{
|
||||
return GetString("Exception_InvalidToSerializeIn3Bytes");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value cannot be negative.
|
||||
/// </summary>
|
||||
internal static string Exception_NumberShouldNotBeNegative
|
||||
{
|
||||
get { return GetString("Exception_NumberShouldNotBeNegative"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value cannot be negative.
|
||||
/// </summary>
|
||||
internal static string FormatException_NumberShouldNotBeNegative()
|
||||
{
|
||||
return GetString("Exception_NumberShouldNotBeNegative");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Argument cannot be null or empty string.
|
||||
/// </summary>
|
||||
internal static string ArgumentCannotBeNullOrEmpty
|
||||
{
|
||||
get { return GetString("ArgumentCannotBeNullOrEmpty"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Argument cannot be null or empty string.
|
||||
/// </summary>
|
||||
internal static string FormatArgumentCannotBeNullOrEmpty()
|
||||
{
|
||||
return GetString("ArgumentCannotBeNullOrEmpty");
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Exception_KeyLengthIsExceeded" xml:space="preserve">
|
||||
<value>The key cannot be longer than '{0}' when encoded with UTF-8.</value>
|
||||
</data>
|
||||
<data name="Exception_InvalidSessionEstablishment" xml:space="preserve">
|
||||
<value>The session cannot be established after the response has started.</value>
|
||||
</data>
|
||||
<data name="Exception_InvalidToSerializeIn2Bytes" xml:space="preserve">
|
||||
<value>The value cannot be serialized in two bytes.</value>
|
||||
</data>
|
||||
<data name="Exception_InvalidToSerializeIn3Bytes" xml:space="preserve">
|
||||
<value>The value cannot be serialized in three bytes.</value>
|
||||
</data>
|
||||
<data name="Exception_NumberShouldNotBeNegative" xml:space="preserve">
|
||||
<value>The value cannot be negative.</value>
|
||||
</data>
|
||||
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
|
||||
<value>Argument cannot be null or empty string.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents defaults for the Session.
|
||||
/// </summary>
|
||||
public static class SessionDefaults
|
||||
{
|
||||
/// <summary>
|
||||
/// Represent the default cookie name, which is ".AspNetCore.Session".
|
||||
/// </summary>
|
||||
public static readonly string CookieName = ".AspNetCore.Session";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the default path used to create the cookie, which is "/".
|
||||
/// </summary>
|
||||
public static readonly string CookiePath = "/";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
public class SessionFeature : ISessionFeature
|
||||
{
|
||||
public ISession Session { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables the session state for the application.
|
||||
/// </summary>
|
||||
public class SessionMiddleware
|
||||
{
|
||||
private static readonly RandomNumberGenerator CryptoRandom = RandomNumberGenerator.Create();
|
||||
private const int SessionKeyLength = 36; // "382c74c3-721d-4f34-80e5-57657b6cbc27"
|
||||
private static readonly Func<bool> ReturnTrue = () => true;
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly SessionOptions _options;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ISessionStore _sessionStore;
|
||||
private readonly IDataProtector _dataProtector;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SessionMiddleware"/>.
|
||||
/// </summary>
|
||||
/// <param name="next">The <see cref="RequestDelegate"/> representing the next middleware in the pipeline.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> representing the factory that used to create logger instances.</param>
|
||||
/// <param name="dataProtectionProvider">The <see cref="IDataProtectionProvider"/> used to protect and verify the cookie.</param>
|
||||
/// <param name="sessionStore">The <see cref="ISessionStore"/> representing the session store.</param>
|
||||
/// <param name="options">The session configuration options.</param>
|
||||
public SessionMiddleware(
|
||||
RequestDelegate next,
|
||||
ILoggerFactory loggerFactory,
|
||||
IDataProtectionProvider dataProtectionProvider,
|
||||
ISessionStore sessionStore,
|
||||
IOptions<SessionOptions> options)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(next));
|
||||
}
|
||||
|
||||
if (loggerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
if (dataProtectionProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dataProtectionProvider));
|
||||
}
|
||||
|
||||
if (sessionStore == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sessionStore));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
_next = next;
|
||||
_logger = loggerFactory.CreateLogger<SessionMiddleware>();
|
||||
_dataProtector = dataProtectionProvider.CreateProtector(nameof(SessionMiddleware));
|
||||
_options = options.Value;
|
||||
_sessionStore = sessionStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the logic of the middleware.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="HttpContext"/>.</param>
|
||||
/// <returns>A <see cref="Task"/> that completes when the middleware has completed processing.</returns>
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var isNewSessionKey = false;
|
||||
Func<bool> tryEstablishSession = ReturnTrue;
|
||||
var cookieValue = context.Request.Cookies[_options.Cookie.Name];
|
||||
var sessionKey = CookieProtection.Unprotect(_dataProtector, cookieValue, _logger);
|
||||
if (string.IsNullOrWhiteSpace(sessionKey) || sessionKey.Length != SessionKeyLength)
|
||||
{
|
||||
// No valid cookie, new session.
|
||||
var guidBytes = new byte[16];
|
||||
CryptoRandom.GetBytes(guidBytes);
|
||||
sessionKey = new Guid(guidBytes).ToString();
|
||||
cookieValue = CookieProtection.Protect(_dataProtector, sessionKey);
|
||||
var establisher = new SessionEstablisher(context, cookieValue, _options);
|
||||
tryEstablishSession = establisher.TryEstablishSession;
|
||||
isNewSessionKey = true;
|
||||
}
|
||||
|
||||
var feature = new SessionFeature();
|
||||
feature.Session = _sessionStore.Create(sessionKey, _options.IdleTimeout, _options.IOTimeout, tryEstablishSession, isNewSessionKey);
|
||||
context.Features.Set<ISessionFeature>(feature);
|
||||
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Features.Set<ISessionFeature>(null);
|
||||
|
||||
if (feature.Session != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await feature.Session.CommitAsync(context.RequestAborted);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.SessionCommitCanceled();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorClosingTheSession(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SessionEstablisher
|
||||
{
|
||||
private readonly HttpContext _context;
|
||||
private readonly string _cookieValue;
|
||||
private readonly SessionOptions _options;
|
||||
private bool _shouldEstablishSession;
|
||||
|
||||
public SessionEstablisher(HttpContext context, string cookieValue, SessionOptions options)
|
||||
{
|
||||
_context = context;
|
||||
_cookieValue = cookieValue;
|
||||
_options = options;
|
||||
context.Response.OnStarting(OnStartingCallback, state: this);
|
||||
}
|
||||
|
||||
private static Task OnStartingCallback(object state)
|
||||
{
|
||||
var establisher = (SessionEstablisher)state;
|
||||
if (establisher._shouldEstablishSession)
|
||||
{
|
||||
establisher.SetCookie();
|
||||
}
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private void SetCookie()
|
||||
{
|
||||
var cookieOptions = _options.Cookie.Build(_context);
|
||||
|
||||
_context.Response.Cookies.Append(_options.Cookie.Name, _cookieValue, cookieOptions);
|
||||
|
||||
_context.Response.Headers["Cache-Control"] = "no-cache";
|
||||
_context.Response.Headers["Pragma"] = "no-cache";
|
||||
_context.Response.Headers["Expires"] = "-1";
|
||||
}
|
||||
|
||||
// Returns true if the session has already been established, or if it still can be because the response has not been sent.
|
||||
internal bool TryEstablishSession()
|
||||
{
|
||||
return (_shouldEstablishSession |= !_context.Response.HasStarted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Session;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for adding the <see cref="SessionMiddleware"/> to an application.
|
||||
/// </summary>
|
||||
public static class SessionMiddlewareExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the <see cref="SessionMiddleware"/> to automatically enable session state for the application.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
|
||||
public static IApplicationBuilder UseSession(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<SessionMiddleware>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <see cref="SessionMiddleware"/> to automatically enable session state for the application.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <param name="options">The <see cref="SessionOptions"/>.</param>
|
||||
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
|
||||
public static IApplicationBuilder UseSession(this IApplicationBuilder app, SessionOptions options)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
return app.UseMiddleware<SessionMiddleware>(Options.Create(options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Session;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the session state options for the application.
|
||||
/// </summary>
|
||||
public class SessionOptions
|
||||
{
|
||||
private CookieBuilder _cookieBuilder = new SessionCookieBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// Determines the settings used to create the cookie.
|
||||
/// <para>
|
||||
/// <see cref="CookieBuilder.Name"/> defaults to <see cref="SessionDefaults.CookieName"/>.
|
||||
/// <see cref="CookieBuilder.Path"/> defaults to <see cref="SessionDefaults.CookiePath"/>.
|
||||
/// <see cref="CookieBuilder.SameSite"/> defaults to <see cref="SameSiteMode.Lax"/>.
|
||||
/// <see cref="CookieBuilder.HttpOnly"/> defaults to <c>true</c>
|
||||
/// <see cref="CookieBuilder.IsEssential"/> defaults to <c>false</c>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public CookieBuilder Cookie
|
||||
{
|
||||
get => _cookieBuilder;
|
||||
set => _cookieBuilder = value ?? throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The IdleTimeout indicates how long the session can be idle before its contents are abandoned. Each session access
|
||||
/// resets the timeout. Note this only applies to the content of the session, not the cookie.
|
||||
/// </summary>
|
||||
public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromMinutes(20);
|
||||
|
||||
/// <summary>
|
||||
/// The maximim amount of time allowed to load a session from the store or to commit it back to the store.
|
||||
/// Note this may only apply to asynchronous operations. This timeout can be disabled using <see cref="Timeout.InfiniteTimeSpan"/>.
|
||||
/// </summary>
|
||||
public TimeSpan IOTimeout { get; set; } = TimeSpan.FromMinutes(1);
|
||||
|
||||
#region Obsolete API
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Name"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines the cookie name used to persist the session ID.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Name) + ".")]
|
||||
public string CookieName { get => Cookie.Name; set => Cookie.Name = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Domain"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines the domain used to create the cookie. Is not provided by default.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Domain) + ".")]
|
||||
public string CookieDomain { get => Cookie.Domain; set => Cookie.Domain = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Path"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines the path used to create the cookie.
|
||||
/// Defaults to <see cref="SessionDefaults.CookiePath"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Path) + ".")]
|
||||
public string CookiePath { get => Cookie.Path; set => Cookie.Path = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.HttpOnly"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines if the browser should allow the cookie to be accessed by client-side JavaScript. The
|
||||
/// default is true, which means the cookie will only be passed to HTTP requests and is not made available
|
||||
/// to script on the page.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.HttpOnly) + ".")]
|
||||
public bool CookieHttpOnly { get => Cookie.HttpOnly; set => Cookie.HttpOnly = value; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.SecurePolicy"/> on <see cref="Cookie"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Determines if the cookie should only be transmitted on HTTPS requests.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.SecurePolicy) + ".")]
|
||||
public CookieSecurePolicy CookieSecure { get => Cookie.SecurePolicy; set => Cookie.SecurePolicy = value; }
|
||||
#endregion
|
||||
|
||||
private class SessionCookieBuilder : CookieBuilder
|
||||
{
|
||||
public SessionCookieBuilder()
|
||||
{
|
||||
Name = SessionDefaults.CookieName;
|
||||
Path = SessionDefaults.CookiePath;
|
||||
SecurePolicy = CookieSecurePolicy.None;
|
||||
SameSite = SameSiteMode.Lax;
|
||||
HttpOnly = true;
|
||||
// Session is considered non-essential as it's designed for ephemeral data.
|
||||
IsEssential = false;
|
||||
}
|
||||
|
||||
public override TimeSpan? Expiration
|
||||
{
|
||||
get => null;
|
||||
set => throw new InvalidOperationException(nameof(Expiration) + " cannot be set for the cookie defined by " + nameof(SessionOptions));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Session;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for adding session services to the DI container.
|
||||
/// </summary>
|
||||
public static class SessionServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds services required for application session state.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
|
||||
public static IServiceCollection AddSession(this IServiceCollection services)
|
||||
{
|
||||
if (services == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(services));
|
||||
}
|
||||
|
||||
services.TryAddTransient<ISessionStore, DistributedSessionStore>();
|
||||
services.AddDataProtection();
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services required for application session state.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
|
||||
/// <param name="configure">The session options to configure the middleware with.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
|
||||
public static IServiceCollection AddSession(this IServiceCollection services, Action<SessionOptions> configure)
|
||||
{
|
||||
if (services == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(services));
|
||||
}
|
||||
|
||||
if (configure == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configure));
|
||||
}
|
||||
|
||||
services.Configure(configure);
|
||||
services.AddSession();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Session
|
||||
{
|
||||
// A byte[] equality comparer based on the SipHash-2-4 algorithm. Key differences:
|
||||
// (a) we output 32-bit hashes instead of 64-bit hashes, and
|
||||
// (b) we don't care about endianness since hashes are used only in hash tables
|
||||
// and aren't returned to user code.
|
||||
//
|
||||
// Derived from the implementation in SignalR and modified to address byte[] instead of string. This derived version is not for cryptographic use, just hash codes.
|
||||
// https://github.com/aspnet/SignalR-Server/blob/75f74169c81a51780f195d06b798302b2d76dbde/src/Microsoft.AspNetCore.SignalR.Server/Infrastructure/SipHashBasedStringEqualityComparer.cs
|
||||
// Derivative work of https://github.com/tanglebones/ch-siphash.
|
||||
internal static class SipHash
|
||||
{
|
||||
internal static int GetHashCode(byte[] bytes)
|
||||
{
|
||||
// Assume SipHash-2-4 is a strong PRF, therefore truncation to 32 bits is acceptable.
|
||||
return (int)SipHash_2_4_UlongCast_ForcedInline(bytes);
|
||||
}
|
||||
|
||||
private static ulong SipHash_2_4_UlongCast_ForcedInline(byte[] bytes)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
ulong v0 = 0x736f6d6570736575;
|
||||
ulong v1 = 0x646f72616e646f6d;
|
||||
ulong v2 = 0x6c7967656e657261;
|
||||
ulong v3 = 0x7465646279746573;
|
||||
|
||||
uint inlen = (uint)bytes.Length;
|
||||
fixed (byte* finb = bytes)
|
||||
{
|
||||
var b = ((ulong)inlen) << 56;
|
||||
|
||||
if (inlen > 0)
|
||||
{
|
||||
var inb = finb;
|
||||
var left = inlen & 7;
|
||||
var end = inb + inlen - left;
|
||||
var linb = (ulong*)finb;
|
||||
var lend = (ulong*)end;
|
||||
for (; linb < lend; ++linb)
|
||||
{
|
||||
v3 ^= *linb;
|
||||
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
|
||||
v0 ^= *linb;
|
||||
}
|
||||
for (var i = 0; i < left; ++i)
|
||||
{
|
||||
b |= ((ulong)end[i]) << (8 * i);
|
||||
}
|
||||
}
|
||||
|
||||
v3 ^= b;
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
v0 ^= b;
|
||||
v2 ^= 0xff;
|
||||
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
v0 += v1;
|
||||
v1 = (v1 << 13) | (v1 >> (64 - 13));
|
||||
v1 ^= v0;
|
||||
v0 = (v0 << 32) | (v0 >> (64 - 32));
|
||||
|
||||
v2 += v3;
|
||||
v3 = (v3 << 16) | (v3 >> (64 - 16));
|
||||
v3 ^= v2;
|
||||
|
||||
v0 += v3;
|
||||
v3 = (v3 << 21) | (v3 >> (64 - 21));
|
||||
v3 ^= v0;
|
||||
|
||||
v2 += v1;
|
||||
v1 = (v1 << 17) | (v1 >> (64 - 17));
|
||||
v1 ^= v2;
|
||||
v2 = (v2 << 32) | (v2 >> (64 - 32));
|
||||
}
|
||||
|
||||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,687 @@
|
|||
{
|
||||
"AssemblyIdentity": "Microsoft.AspNetCore.Session, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
|
||||
"Types": [
|
||||
{
|
||||
"Name": "Microsoft.Extensions.DependencyInjection.SessionServiceCollectionExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddSession",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "services",
|
||||
"Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "AddSession",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "services",
|
||||
"Type": "Microsoft.Extensions.DependencyInjection.IServiceCollection"
|
||||
},
|
||||
{
|
||||
"Name": "configure",
|
||||
"Type": "System.Action<Microsoft.AspNetCore.Builder.SessionOptions>"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.Extensions.DependencyInjection.IServiceCollection",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Builder.SessionMiddlewareExtensions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "UseSession",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "app",
|
||||
"Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "UseSession",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "app",
|
||||
"Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
|
||||
},
|
||||
{
|
||||
"Name": "options",
|
||||
"Type": "Microsoft.AspNetCore.Builder.SessionOptions"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
|
||||
"Static": true,
|
||||
"Extension": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Builder.SessionOptions",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Cookie",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.AspNetCore.Http.CookieBuilder",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_Cookie",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "Microsoft.AspNetCore.Http.CookieBuilder"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_IdleTimeout",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.TimeSpan",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_IdleTimeout",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.TimeSpan"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_IOTimeout",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.TimeSpan",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_IOTimeout",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.TimeSpan"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_CookieName",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_CookieName",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_CookieDomain",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_CookieDomain",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_CookiePath",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_CookiePath",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_CookieHttpOnly",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Boolean",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_CookieHttpOnly",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.Boolean"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_CookieSecure",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.AspNetCore.Http.CookieSecurePolicy",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_CookieSecure",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "Microsoft.AspNetCore.Http.CookieSecurePolicy"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Session.DistributedSession",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [
|
||||
"Microsoft.AspNetCore.Http.ISession"
|
||||
],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_IsAvailable",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Boolean",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Id",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Keys",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Collections.Generic.IEnumerable<System.String>",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "TryGetValue",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "key",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.Byte[]",
|
||||
"Direction": "Out"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Boolean",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Set",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "key",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "System.Byte[]"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Remove",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "key",
|
||||
"Type": "System.String"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Clear",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.Void",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "LoadAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "CommitAsync",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cancellationToken",
|
||||
"Type": "System.Threading.CancellationToken",
|
||||
"DefaultValue": "default(System.Threading.CancellationToken)"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cache",
|
||||
"Type": "Microsoft.Extensions.Caching.Distributed.IDistributedCache"
|
||||
},
|
||||
{
|
||||
"Name": "sessionKey",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "idleTimeout",
|
||||
"Type": "System.TimeSpan"
|
||||
},
|
||||
{
|
||||
"Name": "ioTimeout",
|
||||
"Type": "System.TimeSpan"
|
||||
},
|
||||
{
|
||||
"Name": "tryEstablishSession",
|
||||
"Type": "System.Func<System.Boolean>"
|
||||
},
|
||||
{
|
||||
"Name": "loggerFactory",
|
||||
"Type": "Microsoft.Extensions.Logging.ILoggerFactory"
|
||||
},
|
||||
{
|
||||
"Name": "isNewSessionKey",
|
||||
"Type": "System.Boolean"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Session.DistributedSessionStore",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [
|
||||
"Microsoft.AspNetCore.Session.ISessionStore"
|
||||
],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Create",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "sessionKey",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "idleTimeout",
|
||||
"Type": "System.TimeSpan"
|
||||
},
|
||||
{
|
||||
"Name": "ioTimeout",
|
||||
"Type": "System.TimeSpan"
|
||||
},
|
||||
{
|
||||
"Name": "tryEstablishSession",
|
||||
"Type": "System.Func<System.Boolean>"
|
||||
},
|
||||
{
|
||||
"Name": "isNewSessionKey",
|
||||
"Type": "System.Boolean"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Session.ISessionStore",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "cache",
|
||||
"Type": "Microsoft.Extensions.Caching.Distributed.IDistributedCache"
|
||||
},
|
||||
{
|
||||
"Name": "loggerFactory",
|
||||
"Type": "Microsoft.Extensions.Logging.ILoggerFactory"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Session.ISessionStore",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Interface",
|
||||
"Abstract": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Create",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "sessionKey",
|
||||
"Type": "System.String"
|
||||
},
|
||||
{
|
||||
"Name": "idleTimeout",
|
||||
"Type": "System.TimeSpan"
|
||||
},
|
||||
{
|
||||
"Name": "ioTimeout",
|
||||
"Type": "System.TimeSpan"
|
||||
},
|
||||
{
|
||||
"Name": "tryEstablishSession",
|
||||
"Type": "System.Func<System.Boolean>"
|
||||
},
|
||||
{
|
||||
"Name": "isNewSessionKey",
|
||||
"Type": "System.Boolean"
|
||||
}
|
||||
],
|
||||
"ReturnType": "Microsoft.AspNetCore.Http.ISession",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Session.SessionDefaults",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"Abstract": true,
|
||||
"Static": true,
|
||||
"Sealed": true,
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "CookieName",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Field",
|
||||
"Name": "CookiePath",
|
||||
"Parameters": [],
|
||||
"ReturnType": "System.String",
|
||||
"Static": true,
|
||||
"ReadOnly": true,
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Session.SessionFeature",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [
|
||||
"Microsoft.AspNetCore.Http.Features.ISessionFeature"
|
||||
],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "get_Session",
|
||||
"Parameters": [],
|
||||
"ReturnType": "Microsoft.AspNetCore.Http.ISession",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.Features.ISessionFeature",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "set_Session",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "value",
|
||||
"Type": "Microsoft.AspNetCore.Http.ISession"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Void",
|
||||
"Sealed": true,
|
||||
"Virtual": true,
|
||||
"ImplementedInterface": "Microsoft.AspNetCore.Http.Features.ISessionFeature",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
},
|
||||
{
|
||||
"Name": "Microsoft.AspNetCore.Session.SessionMiddleware",
|
||||
"Visibility": "Public",
|
||||
"Kind": "Class",
|
||||
"ImplementedInterfaces": [],
|
||||
"Members": [
|
||||
{
|
||||
"Kind": "Method",
|
||||
"Name": "Invoke",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "context",
|
||||
"Type": "Microsoft.AspNetCore.Http.HttpContext"
|
||||
}
|
||||
],
|
||||
"ReturnType": "System.Threading.Tasks.Task",
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
},
|
||||
{
|
||||
"Kind": "Constructor",
|
||||
"Name": ".ctor",
|
||||
"Parameters": [
|
||||
{
|
||||
"Name": "next",
|
||||
"Type": "Microsoft.AspNetCore.Http.RequestDelegate"
|
||||
},
|
||||
{
|
||||
"Name": "loggerFactory",
|
||||
"Type": "Microsoft.Extensions.Logging.ILoggerFactory"
|
||||
},
|
||||
{
|
||||
"Name": "dataProtectionProvider",
|
||||
"Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider"
|
||||
},
|
||||
{
|
||||
"Name": "sessionStore",
|
||||
"Type": "Microsoft.AspNetCore.Session.ISessionStore"
|
||||
},
|
||||
{
|
||||
"Name": "options",
|
||||
"Type": "Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Builder.SessionOptions>"
|
||||
}
|
||||
],
|
||||
"Visibility": "Public",
|
||||
"GenericParameter": []
|
||||
}
|
||||
],
|
||||
"GenericParameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<Project>
|
||||
<Import Project="..\Directory.Build.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<DeveloperBuildTestTfms>netcoreapp2.1</DeveloperBuildTestTfms>
|
||||
<StandardTestTfms>$(DeveloperBuildTestTfms)</StandardTestTfms>
|
||||
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' ">netcoreapp2.1;netcoreapp2.0</StandardTestTfms>
|
||||
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(StandardTestTfms);net461</StandardTestTfms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Session\Microsoft.AspNetCore.Session.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="$(MicrosoftAspNetCoreTestHostPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(MicrosoftExtensionsLoggingTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,12 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>2.1.1</VersionPrefix>
|
||||
<VersionSuffix>rtm</VersionSuffix>
|
||||
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' == 'rtm' ">$(VersionPrefix)</PackageVersion>
|
||||
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' != 'rtm' ">$(VersionPrefix)-$(VersionSuffix)-final</PackageVersion>
|
||||
<BuildNumber Condition="'$(BuildNumber)' == ''">t000</BuildNumber>
|
||||
<FeatureBranchVersionPrefix Condition="'$(FeatureBranchVersionPrefix)' == ''">a-</FeatureBranchVersionPrefix>
|
||||
<VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(FeatureBranchVersionSuffix)' != ''">$(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-'))</VersionSuffix>
|
||||
<VersionSuffix Condition="'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue