Add docs for Session, Diagnostics.EntityFrameworkCore, MiddlewareAnalysis and HeaderPropagation (#26720)

This commit is contained in:
Stephen Halter 2020-10-09 20:38:45 -07:00 committed by GitHub
parent d694724475
commit ff6d1986ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 171 additions and 13 deletions

View File

@ -7,6 +7,10 @@ using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Http namespace Microsoft.AspNetCore.Http
{ {
/// <summary>
/// Stores user data while the user browses a web application. Session state uses a store maintained by the application
/// to persist data across requests from a client. The session data is backed by a cache and considered ephemeral data.
/// </summary>
public interface ISession public interface ISession
{ {
/// <summary> /// <summary>

View File

@ -3,8 +3,14 @@
namespace Microsoft.AspNetCore.Http.Features namespace Microsoft.AspNetCore.Http.Features
{ {
/// <summary>
/// Provides access to the <see cref="ISession"/> for the current request.
/// </summary>
public interface ISessionFeature public interface ISessionFeature
{ {
/// <summary>
/// The <see cref="ISession"/> for the current request.
/// </summary>
ISession Session { get; set; } ISession Session { get; set; }
} }
} }

View File

@ -16,17 +16,33 @@ using Microsoft.Extensions.Options;
#nullable enable #nullable enable
namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore namespace Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
{ {
/// <summary>
/// An <see cref="IDeveloperPageExceptionFilter"/> that captures database-related exceptions that can be resolved by using Entity Framework migrations.
/// When these exceptions occur, an HTML response with details about possible actions to resolve the issue is generated.
/// </summary>
/// <remarks>
/// This should only be enabled in the Development environment.
/// </remarks>
public sealed class DatabaseDeveloperPageExceptionFilter : IDeveloperPageExceptionFilter public sealed class DatabaseDeveloperPageExceptionFilter : IDeveloperPageExceptionFilter
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly DatabaseErrorPageOptions _options; private readonly DatabaseErrorPageOptions _options;
/// <summary>
/// Initializes a new instance of <see cref="DatabaseDeveloperPageExceptionFilter"/>.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/>.</param>
/// <param name="options">The <see cref="IOptions{DatabaseErrorPageOptions}"/>.</param>
public DatabaseDeveloperPageExceptionFilter(ILogger<DatabaseDeveloperPageExceptionFilter> logger, IOptions<DatabaseErrorPageOptions> options) public DatabaseDeveloperPageExceptionFilter(ILogger<DatabaseDeveloperPageExceptionFilter> logger, IOptions<DatabaseErrorPageOptions> options)
{ {
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_options = options?.Value ?? throw new ArgumentNullException(nameof(options)); _options = options?.Value ?? throw new ArgumentNullException(nameof(options));
} }
/// <summary>
/// Handle <see cref="DbException"/> errors and output an HTML response with additional details.
/// </summary>
/// <inheritdoc />
public async Task HandleExceptionAsync(ErrorContext errorContext, Func<ErrorContext, Task> next) public async Task HandleExceptionAsync(ErrorContext errorContext, Func<ErrorContext, Task> next)
{ {
if (!(errorContext.Exception is DbException)) if (!(errorContext.Exception is DbException))

View File

@ -15,10 +15,14 @@ namespace Microsoft.Extensions.DependencyInjection
public static class DatabaseDeveloperPageExceptionFilterServiceExtensions public static class DatabaseDeveloperPageExceptionFilterServiceExtensions
{ {
/// <summary> /// <summary>
/// Add response caching services. /// In combination with UseDeveloperExceptionPage, this captures database-related exceptions that can be resolved by using Entity Framework migrations.
/// When these exceptions occur, an HTML response with details about possible actions to resolve the issue is generated.
/// </summary> /// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> for adding services.</param> /// <param name="services">The <see cref="IServiceCollection"/> for adding services.</param>
/// <returns></returns> /// <returns></returns>
/// <remarks>
/// This should only be enabled in the Development environment.
/// </remarks>
public static IServiceCollection AddDatabaseDeveloperPageExceptionFilter(this IServiceCollection services) public static IServiceCollection AddDatabaseDeveloperPageExceptionFilter(this IServiceCollection services)
{ {
if (services == null) if (services == null)

View File

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Description>ASP.NET Core middleware for Entity Framework Core error pages. Use this middleware to detect and diagnose errors with Entity Framework Core migrations.</Description> <Description>ASP.NET Core middleware for Entity Framework Core error pages. Use this middleware to detect and diagnose errors with Entity Framework Core migrations.</Description>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks> <TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NoWarn>$(NoWarn);CS1591</NoWarn> <NoWarn>$(NoWarn.Replace('1591', ''))</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;diagnostics;entityframeworkcore</PackageTags> <PackageTags>aspnetcore;diagnostics;entityframeworkcore</PackageTags>
</PropertyGroup> </PropertyGroup>

View File

@ -17,6 +17,9 @@ namespace Microsoft.AspNetCore.Builder
/// </summary> /// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param> /// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
/// <returns>A reference to the <paramref name="app"/> after the operation has completed.</returns> /// <returns>A reference to the <paramref name="app"/> after the operation has completed.</returns>
/// <remarks>
/// This should only be enabled in the Development environment.
/// </remarks>
public static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app) public static IApplicationBuilder UseDeveloperExceptionPage(this IApplicationBuilder app)
{ {
if (app == null) if (app == null)
@ -33,6 +36,9 @@ namespace Microsoft.AspNetCore.Builder
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param> /// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
/// <param name="options">A <see cref="DeveloperExceptionPageOptions"/> that specifies options for the middleware.</param> /// <param name="options">A <see cref="DeveloperExceptionPageOptions"/> that specifies options for the middleware.</param>
/// <returns>A reference to the <paramref name="app"/> after the operation has completed.</returns> /// <returns>A reference to the <paramref name="app"/> after the operation has completed.</returns>
/// <remarks>
/// This should only be enabled in the Development environment.
/// </remarks>
public static IApplicationBuilder UseDeveloperExceptionPage( public static IApplicationBuilder UseDeveloperExceptionPage(
this IApplicationBuilder app, this IApplicationBuilder app,
DeveloperExceptionPageOptions options) DeveloperExceptionPageOptions options)

View File

@ -8,6 +8,9 @@ using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
/// <summary>
/// <see cref="IApplicationBuilder"/> extension methods for <see cref="HeaderPropagationMiddleware"/> which propagates request headers to an <see cref="HttpClient"/>.
/// </summary>
public static class HeaderPropagationApplicationBuilderExtensions public static class HeaderPropagationApplicationBuilderExtensions
{ {
private static readonly string _unableToFindServices = string.Format( private static readonly string _unableToFindServices = string.Format(

View File

@ -7,6 +7,9 @@ using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
/// <summary>
/// <see cref="IHttpClientBuilder"/> extension methods for <see cref="HeaderPropagationMiddleware"/> which propagates request headers to an <see cref="System.Net.Http.HttpClient"/>.
/// </summary>
public static class HeaderPropagationHttpClientBuilderExtensions public static class HeaderPropagationHttpClientBuilderExtensions
{ {
/// <summary> /// <summary>

View File

@ -8,6 +8,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
/// <summary>
/// <see cref="IServiceCollection"/> extension methods for <see cref="HeaderPropagationMiddleware"/> which propagates request headers to an <see cref="System.Net.Http.HttpClient"/>.
/// </summary>
public static class HeaderPropagationServiceCollectionExtensions public static class HeaderPropagationServiceCollectionExtensions
{ {
/// <summary> /// <summary>

View File

@ -12,7 +12,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.HeaderPropagation namespace Microsoft.AspNetCore.HeaderPropagation
{ {
/// <summary> /// <summary>
/// A Middleware for propagating headers to a <see cref="HttpClient"/>. /// A Middleware for propagating headers to an <see cref="HttpClient"/>.
/// </summary> /// </summary>
public class HeaderPropagationMiddleware public class HeaderPropagationMiddleware
{ {
@ -20,6 +20,14 @@ namespace Microsoft.AspNetCore.HeaderPropagation
private readonly HeaderPropagationOptions _options; private readonly HeaderPropagationOptions _options;
private readonly HeaderPropagationValues _values; private readonly HeaderPropagationValues _values;
/// <summary>
/// Initializes a new instance of <see cref="HeaderPropagationMiddleware"/>.
/// </summary>
/// <param name="next">The next middleware in the pipeline.</param>
/// <param name="options">The <see cref="IOptions{HeaderPropagationOptions}"/>.</param>
/// <param name="values">
/// The <see cref="HeaderPropagationValues"/> that stores the request headers to be propagated in an <see cref="System.Threading.AsyncLocal{T}"/>
/// </param>
public HeaderPropagationMiddleware(RequestDelegate next, IOptions<HeaderPropagationOptions> options, HeaderPropagationValues values) public HeaderPropagationMiddleware(RequestDelegate next, IOptions<HeaderPropagationOptions> options, HeaderPropagationValues values)
{ {
_next = next ?? throw new ArgumentNullException(nameof(next)); _next = next ?? throw new ArgumentNullException(nameof(next));
@ -33,6 +41,10 @@ namespace Microsoft.AspNetCore.HeaderPropagation
_values = values ?? throw new ArgumentNullException(nameof(values)); _values = values ?? throw new ArgumentNullException(nameof(values));
} }
/// <summary>
/// Executes the middleware that stores the request headers to be propagated in using <see cref="HeaderPropagationValues"/>.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> for the current request.</param>
public Task Invoke(HttpContext context) public Task Invoke(HttpContext context)
{ {
// We need to intialize the headers because the message handler will use this to detect misconfiguration. // We need to intialize the headers because the message handler will use this to detect misconfiguration.

View File

@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Description>ASP.NET Core middleware to propagate HTTP headers from the incoming request to the outgoing HTTP Client requests</Description> <Description>ASP.NET Core middleware to propagate HTTP headers from the incoming request to the outgoing HTTP Client requests</Description>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework> <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn> <NoWarn>$(NoWarn.Replace('1591', ''))</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;httpclient</PackageTags> <PackageTags>aspnetcore;httpclient</PackageTags>
</PropertyGroup> </PropertyGroup>

View File

@ -9,10 +9,18 @@ using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.MiddlewareAnalysis namespace Microsoft.AspNetCore.MiddlewareAnalysis
{ {
/// <summary>
/// An <see cref="IApplicationBuilder"/> decorator used by <see cref="AnalysisStartupFilter"/>
/// to add <see cref="AnalysisMiddleware"/> before and after each other middleware in the pipeline.
/// </summary>
public class AnalysisBuilder : IApplicationBuilder public class AnalysisBuilder : IApplicationBuilder
{ {
private const string NextMiddlewareName = "analysis.NextMiddlewareName"; private const string NextMiddlewareName = "analysis.NextMiddlewareName";
/// <summary>
/// Initializes a new instance of <see cref="AnalysisBuilder"/>.
/// </summary>
/// <param name="inner">The <see cref="IApplicationBuilder"/> to decorate.</param>
public AnalysisBuilder(IApplicationBuilder inner) public AnalysisBuilder(IApplicationBuilder inner)
{ {
InnerBuilder = inner; InnerBuilder = inner;
@ -20,22 +28,26 @@ namespace Microsoft.AspNetCore.MiddlewareAnalysis
private IApplicationBuilder InnerBuilder { get; } private IApplicationBuilder InnerBuilder { get; }
/// <inheritdoc />
public IServiceProvider ApplicationServices public IServiceProvider ApplicationServices
{ {
get { return InnerBuilder.ApplicationServices; } get { return InnerBuilder.ApplicationServices; }
set { InnerBuilder.ApplicationServices = value; } set { InnerBuilder.ApplicationServices = value; }
} }
/// <inheritdoc />
public IDictionary<string, object> Properties public IDictionary<string, object> Properties
{ {
get { return InnerBuilder.Properties; } get { return InnerBuilder.Properties; }
} }
/// <inheritdoc />
public IFeatureCollection ServerFeatures public IFeatureCollection ServerFeatures
{ {
get { return InnerBuilder.ServerFeatures;} get { return InnerBuilder.ServerFeatures;}
} }
/// <inheritdoc />
public RequestDelegate Build() public RequestDelegate Build()
{ {
// Add one maker at the end before the default 404 middleware (or any fancy Join middleware). // Add one maker at the end before the default 404 middleware (or any fancy Join middleware).
@ -43,11 +55,13 @@ namespace Microsoft.AspNetCore.MiddlewareAnalysis
.Build(); .Build();
} }
/// <inheritdoc />
public IApplicationBuilder New() public IApplicationBuilder New()
{ {
return new AnalysisBuilder(InnerBuilder.New()); return new AnalysisBuilder(InnerBuilder.New());
} }
/// <inheritdoc />
public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{ {
string middlewareName = string.Empty; // UseMiddleware doesn't work with null params. string middlewareName = string.Empty; // UseMiddleware doesn't work with null params.

View File

@ -8,6 +8,10 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.MiddlewareAnalysis namespace Microsoft.AspNetCore.MiddlewareAnalysis
{ {
/// <summary>
/// Middleware that is inserted before and after each other middleware in the pipeline by <see cref="AnalysisBuilder"/>
/// to log to a <see cref="DiagnosticSource"/> when other middleware starts, finishes and throws.
/// </summary>
public class AnalysisMiddleware public class AnalysisMiddleware
{ {
private readonly Guid _instanceId = Guid.NewGuid(); private readonly Guid _instanceId = Guid.NewGuid();
@ -15,6 +19,15 @@ namespace Microsoft.AspNetCore.MiddlewareAnalysis
private readonly DiagnosticSource _diagnostics; private readonly DiagnosticSource _diagnostics;
private readonly string _middlewareName; private readonly string _middlewareName;
/// <summary>
/// Initializes a new instance of <see cref="AnalysisMiddleware"/>.
/// </summary>
/// <param name="next">The next middleware in the pipeline.</param>
/// <param name="diagnosticSource">The <see cref="DiagnosticSource"/> to log when other middleware starts, finishes and throws.</param>
/// <param name="middlewareName">
/// The name of the next middleware in the pipeline. This name is typically retrieved from <see cref="Builder.IApplicationBuilder.Properties"/>
/// using the "analysis.NextMiddlewareName" key.
/// </param>
public AnalysisMiddleware(RequestDelegate next, DiagnosticSource diagnosticSource, string middlewareName) public AnalysisMiddleware(RequestDelegate next, DiagnosticSource diagnosticSource, string middlewareName)
{ {
_next = next; _next = next;
@ -26,6 +39,10 @@ namespace Microsoft.AspNetCore.MiddlewareAnalysis
_middlewareName = middlewareName; _middlewareName = middlewareName;
} }
/// <summary>
/// Executes the middleware that logs to a <see cref="DiagnosticSource"/> when the next middleware starts, finishes and throws.
/// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> for the current request.</param>
public async Task Invoke(HttpContext httpContext) public async Task Invoke(HttpContext httpContext)
{ {
var startTimestamp = Stopwatch.GetTimestamp(); var startTimestamp = Stopwatch.GetTimestamp();

View File

@ -14,7 +14,8 @@ namespace Microsoft.Extensions.DependencyInjection
public static class AnalysisServiceCollectionExtensions public static class AnalysisServiceCollectionExtensions
{ {
/// <summary> /// <summary>
/// Adds diagnostic services to the specified <see cref="IServiceCollection" />. /// Adds diagnostic services to the specified <see cref="IServiceCollection" /> by logging to
/// a <see cref="System.Diagnostics.DiagnosticSource"/> when middleware starts, finishes and throws.
/// </summary> /// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param> /// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns> /// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>

View File

@ -7,8 +7,17 @@ using Microsoft.AspNetCore.Hosting;
namespace Microsoft.AspNetCore.MiddlewareAnalysis namespace Microsoft.AspNetCore.MiddlewareAnalysis
{ {
/// <summary>
/// An <see cref="IStartupFilter"/> that configures the middleware pipeline to log to a <see cref="System.Diagnostics.DiagnosticSource"/>
/// when middleware starts, finishes and throws.
/// </summary>
public class AnalysisStartupFilter : IStartupFilter public class AnalysisStartupFilter : IStartupFilter
{ {
/// <summary>
/// Wraps the <see cref="IApplicationBuilder"/> with <see cref="AnalysisBuilder"/> and directly adds
/// <see cref="AnalysisMiddleware"/> to the end of the middleware pipeline.
/// </summary>
/// <inheritdoc />
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{ {
return builder => return builder =>

View File

@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Description>ASP.NET Core middleware for analyzing middleware in the request pipeline with System.Diagnostics.DiagnosticSource.</Description> <Description>ASP.NET Core middleware for analyzing middleware in the request pipeline with System.Diagnostics.DiagnosticSource.</Description>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework> <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<NoWarn>$(NoWarn);CS1591</NoWarn> <NoWarn>$(NoWarn.Replace('1591', ''))</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;diagnostics</PackageTags> <PackageTags>aspnetcore;diagnostics</PackageTags>
</PropertyGroup> </PropertyGroup>

View File

@ -14,6 +14,9 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Session namespace Microsoft.AspNetCore.Session
{ {
/// <summary>
/// An <see cref="ISession"/> backed by an <see cref="IDistributedCache"/>.
/// </summary>
public class DistributedSession : ISession public class DistributedSession : ISession
{ {
private const int IdByteCount = 16; private const int IdByteCount = 16;
@ -35,6 +38,23 @@ namespace Microsoft.AspNetCore.Session
private string _sessionId; private string _sessionId;
private byte[] _sessionIdBytes; private byte[] _sessionIdBytes;
/// <summary>
/// Initializes a new instance of <see cref="DistributedSession"/>.
/// </summary>
/// <param name="cache">The <see cref="IDistributedCache"/> used to store the session data.</param>
/// <param name="sessionKey">A unique key used to lookup the session.</param>
/// <param name="idleTimeout">How long the session can be inactive (e.g. not accessed) before it will expire.</param>
/// <param name="ioTimeout">
/// The maximum amount of time <see cref="LoadAsync(CancellationToken)"/> and <see cref="CommitAsync(CancellationToken)"/> are allowed take.
/// </param>
/// <param name="tryEstablishSession">
/// A callback invoked during <see cref="Set(string, byte[])"/> to verify that modifying the session is currently valid.
/// If the callback returns <see langword="false"/>, <see cref="Set(string, byte[])"/> throws an <see cref="InvalidOperationException"/>.
/// <see cref="SessionMiddleware"/> provides a callback that returns <see langword="false"/> if the session was not established
/// prior to sending the response.
/// </param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
/// <param name="isNewSessionKey"><see langword="true"/> if establishing a new session; <see langword="false"/> if resuming a session.</param>
public DistributedSession( public DistributedSession(
IDistributedCache cache, IDistributedCache cache,
string sessionKey, string sessionKey,
@ -74,6 +94,7 @@ namespace Microsoft.AspNetCore.Session
_isNewSessionKey = isNewSessionKey; _isNewSessionKey = isNewSessionKey;
} }
/// <inheritdoc />
public bool IsAvailable public bool IsAvailable
{ {
get get
@ -83,6 +104,7 @@ namespace Microsoft.AspNetCore.Session
} }
} }
/// <inheritdoc />
public string Id public string Id
{ {
get get
@ -109,6 +131,7 @@ namespace Microsoft.AspNetCore.Session
} }
} }
/// <inheritdoc/>
public IEnumerable<string> Keys public IEnumerable<string> Keys
{ {
get get
@ -118,12 +141,14 @@ namespace Microsoft.AspNetCore.Session
} }
} }
/// <inheritdoc />
public bool TryGetValue(string key, out byte[] value) public bool TryGetValue(string key, out byte[] value)
{ {
Load(); Load();
return _store.TryGetValue(new EncodedKey(key), out value); return _store.TryGetValue(new EncodedKey(key), out value);
} }
/// <inheritdoc />
public void Set(string key, byte[] value) public void Set(string key, byte[] value)
{ {
if (value == null) if (value == null)
@ -151,12 +176,14 @@ namespace Microsoft.AspNetCore.Session
} }
} }
/// <inheritdoc />
public void Remove(string key) public void Remove(string key)
{ {
Load(); Load();
_isModified |= _store.Remove(new EncodedKey(key)); _isModified |= _store.Remove(new EncodedKey(key));
} }
/// <inheritdoc />
public void Clear() public void Clear()
{ {
Load(); Load();
@ -196,9 +223,10 @@ namespace Microsoft.AspNetCore.Session
} }
} }
// This will throw if called directly and a failure occurs. The user is expected to handle the failures. /// <inheritdoc />
public async Task LoadAsync(CancellationToken cancellationToken = default) public async Task LoadAsync(CancellationToken cancellationToken = default)
{ {
// This will throw if called directly and a failure occurs. The user is expected to handle the failures.
if (!_loaded) if (!_loaded)
{ {
using (var timeout = new CancellationTokenSource(_ioTimeout)) using (var timeout = new CancellationTokenSource(_ioTimeout))
@ -232,6 +260,7 @@ namespace Microsoft.AspNetCore.Session
} }
} }
/// <inheritdoc />
public async Task CommitAsync(CancellationToken cancellationToken = default) public async Task CommitAsync(CancellationToken cancellationToken = default)
{ {
using (var timeout = new CancellationTokenSource(_ioTimeout)) using (var timeout = new CancellationTokenSource(_ioTimeout))
@ -419,6 +448,5 @@ namespace Microsoft.AspNetCore.Session
} }
return output; return output;
} }
} }
} }

View File

@ -8,11 +8,19 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Session namespace Microsoft.AspNetCore.Session
{ {
/// <summary>
/// An <see cref="ISessionStore"/> backed by an <see cref="IDistributedCache"/>.
/// </summary>
public class DistributedSessionStore : ISessionStore public class DistributedSessionStore : ISessionStore
{ {
private readonly IDistributedCache _cache; private readonly IDistributedCache _cache;
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
/// <summary>
/// Initializes a new instance of <see cref="DistributedSessionStore"/>.
/// </summary>
/// <param name="cache">The <see cref="IDistributedCache"/> used to store the session data.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public DistributedSessionStore(IDistributedCache cache, ILoggerFactory loggerFactory) public DistributedSessionStore(IDistributedCache cache, ILoggerFactory loggerFactory)
{ {
if (cache == null) if (cache == null)
@ -29,6 +37,7 @@ namespace Microsoft.AspNetCore.Session
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
} }
/// <inheritdoc />
public ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey) public ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey)
{ {
if (string.IsNullOrEmpty(sessionKey)) if (string.IsNullOrEmpty(sessionKey))

View File

@ -6,8 +6,28 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Session namespace Microsoft.AspNetCore.Session
{ {
/// <summary>
/// Storage for sessions that maintain user data while the user browses a web application.
/// </summary>
public interface ISessionStore public interface ISessionStore
{ {
/// <summary>
/// Create a new or resume an <see cref="ISession"/>.
/// </summary>
/// <param name="sessionKey">A unique key used to lookup the session.</param>
/// <param name="idleTimeout">How long the session can be inactive (e.g. not accessed) before it will expire.</param>
/// <param name="ioTimeout">
/// The maximum amount of time <see cref="ISession.LoadAsync(System.Threading.CancellationToken)"/> and
/// <see cref="ISession.CommitAsync(System.Threading.CancellationToken)"/> are allowed take.
/// </param>
/// <param name="tryEstablishSession">
/// A callback invoked during <see cref="ISession.Set(string, byte[])"/> to verify that modifying the session is currently valid.
/// If the callback returns <see langword="false"/>, <see cref="ISession.Set(string, byte[])"/> should throw an <see cref="InvalidOperationException"/>.
/// <see cref="SessionMiddleware"/> provides a callback that returns <see langword="false"/> if the session was not established
/// prior to sending the response.
/// </param>
/// <param name="isNewSessionKey"><see langword="true"/> if establishing a new session; <see langword="false"/> if resuming a session.</param>
/// <returns>The <see cref="ISession"/> that was created or resumed.</returns>
ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey); ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey);
} }
} }

View File

@ -4,7 +4,7 @@
<Description>ASP.NET Core session state middleware.</Description> <Description>ASP.NET Core session state middleware.</Description>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework> <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp> <IsAspNetCoreApp>true</IsAspNetCoreApp>
<NoWarn>$(NoWarn);CS1591</NoWarn> <NoWarn>$(NoWarn.Replace('1591', ''))</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;session;sessionstate</PackageTags> <PackageTags>aspnetcore;session;sessionstate</PackageTags>

View File

@ -6,8 +6,10 @@ using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Session namespace Microsoft.AspNetCore.Session
{ {
/// <inheritdoc />
public class SessionFeature : ISessionFeature public class SessionFeature : ISessionFeature
{ {
/// <inheritdoc />
public ISession Session { get; set; } public ISession Session { get; set; }
} }
} }

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Description>Helpers for building single-page applications on ASP.NET MVC Core.</Description> <Description>Helpers for building single-page applications on ASP.NET MVC Core.</Description>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework> <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<NoWarn>$(NoWarn.Replace('1591', ''))</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>