#167 Add cancellation tokens and defualt timeouts for Load/CommitAsync.
This commit is contained in:
parent
6f4f34a0bf
commit
1a1e4c309f
|
|
@ -6,6 +6,7 @@ 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;
|
||||
|
|
@ -24,6 +25,7 @@ namespace Microsoft.AspNetCore.Session
|
|||
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;
|
||||
|
|
@ -38,6 +40,7 @@ namespace Microsoft.AspNetCore.Session
|
|||
IDistributedCache cache,
|
||||
string sessionKey,
|
||||
TimeSpan idleTimeout,
|
||||
TimeSpan ioTimeout,
|
||||
Func<bool> tryEstablishSession,
|
||||
ILoggerFactory loggerFactory,
|
||||
bool isNewSessionKey)
|
||||
|
|
@ -65,6 +68,7 @@ namespace Microsoft.AspNetCore.Session
|
|||
_cache = cache;
|
||||
_sessionKey = sessionKey;
|
||||
_idleTimeout = idleTimeout;
|
||||
_ioTimeout = ioTimeout;
|
||||
_tryEstablishSession = tryEstablishSession;
|
||||
_store = new Dictionary<EncodedKey, byte[]>();
|
||||
_logger = loggerFactory.CreateLogger<DistributedSession>();
|
||||
|
|
@ -194,58 +198,68 @@ namespace Microsoft.AspNetCore.Session
|
|||
}
|
||||
|
||||
// This will throw if called directly and a failure occurs. The user is expected to handle the failures.
|
||||
public async Task LoadAsync()
|
||||
public async Task LoadAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (!_loaded)
|
||||
{
|
||||
var data = await _cache.GetAsync(_sessionKey);
|
||||
if (data != null)
|
||||
using (var timeout = new CancellationTokenSource(_ioTimeout))
|
||||
{
|
||||
Deserialize(new MemoryStream(data));
|
||||
}
|
||||
else if (!_isNewSessionKey)
|
||||
{
|
||||
_logger.AccessingExpiredSession(_sessionKey);
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, cancellationToken);
|
||||
var data = await _cache.GetAsync(_sessionKey, cts.Token);
|
||||
if (data != null)
|
||||
{
|
||||
Deserialize(new MemoryStream(data));
|
||||
}
|
||||
else if (!_isNewSessionKey)
|
||||
{
|
||||
_logger.AccessingExpiredSession(_sessionKey);
|
||||
}
|
||||
}
|
||||
_isAvailable = true;
|
||||
_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CommitAsync()
|
||||
public async Task CommitAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (_isModified)
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
using (var timeout = new CancellationTokenSource(_ioTimeout))
|
||||
{
|
||||
if (_logger.IsEnabled(LogLevel.Information))
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, cancellationToken);
|
||||
if (_isModified)
|
||||
{
|
||||
try
|
||||
if (_logger.IsEnabled(LogLevel.Information))
|
||||
{
|
||||
var data = await _cache.GetAsync(_sessionKey);
|
||||
if (data == null)
|
||||
try
|
||||
{
|
||||
_logger.SessionStarted(_sessionKey, Id);
|
||||
var data = await _cache.GetAsync(_sessionKey, cts.Token);
|
||||
if (data == null)
|
||||
{
|
||||
_logger.SessionStarted(_sessionKey, Id);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.SessionCacheReadException(_sessionKey, exception);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.SessionCacheReadException(_sessionKey, exception);
|
||||
}
|
||||
|
||||
var stream = new MemoryStream();
|
||||
Serialize(stream);
|
||||
|
||||
await _cache.SetAsync(
|
||||
_sessionKey,
|
||||
stream.ToArray(),
|
||||
new DistributedCacheEntryOptions().SetSlidingExpiration(_idleTimeout),
|
||||
cts.Token);
|
||||
_isModified = false;
|
||||
_logger.SessionStored(_sessionKey, Id, _store.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _cache.RefreshAsync(_sessionKey, cts.Token);
|
||||
}
|
||||
|
||||
var stream = new MemoryStream();
|
||||
Serialize(stream);
|
||||
|
||||
await _cache.SetAsync(
|
||||
_sessionKey,
|
||||
stream.ToArray(),
|
||||
new DistributedCacheEntryOptions().SetSlidingExpiration(_idleTimeout));
|
||||
|
||||
_isModified = false;
|
||||
_logger.SessionStored(_sessionKey, Id, _store.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _cache.RefreshAsync(_sessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Session
|
|||
_loggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
public ISession Create(string sessionKey, TimeSpan idleTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey)
|
||||
public ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sessionKey))
|
||||
{
|
||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Session
|
|||
throw new ArgumentNullException(nameof(tryEstablishSession));
|
||||
}
|
||||
|
||||
return new DistributedSession(_cache, sessionKey, idleTimeout, tryEstablishSession, _loggerFactory, isNewSessionKey);
|
||||
return new DistributedSession(_cache, sessionKey, idleTimeout, ioTimeout, tryEstablishSession, _loggerFactory, isNewSessionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,6 @@ namespace Microsoft.AspNetCore.Session
|
|||
{
|
||||
public interface ISessionStore
|
||||
{
|
||||
ISession Create(string sessionKey, TimeSpan idleTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey);
|
||||
ISession Create(string sessionKey, TimeSpan idleTimeout, TimeSpan ioTimeout, Func<bool> tryEstablishSession, bool isNewSessionKey);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
|
|
@ -98,7 +99,7 @@ namespace Microsoft.AspNetCore.Session
|
|||
}
|
||||
|
||||
var feature = new SessionFeature();
|
||||
feature.Session = _sessionStore.Create(sessionKey, _options.IdleTimeout, tryEstablishSession, isNewSessionKey);
|
||||
feature.Session = _sessionStore.Create(sessionKey, _options.IdleTimeout, _options.IOTimeout, tryEstablishSession, isNewSessionKey);
|
||||
context.Features.Set<ISessionFeature>(feature);
|
||||
|
||||
try
|
||||
|
|
@ -113,7 +114,7 @@ namespace Microsoft.AspNetCore.Session
|
|||
{
|
||||
try
|
||||
{
|
||||
await feature.Session.CommitAsync();
|
||||
await feature.Session.CommitAsync(context.RequestAborted);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// 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;
|
||||
|
||||
|
|
@ -35,6 +36,12 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// </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>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
[
|
||||
{
|
||||
"TypeId": "public interface Microsoft.AspNetCore.Session.ISessionStore",
|
||||
"MemberId": "Microsoft.AspNetCore.Http.ISession Create(System.String sessionKey, System.TimeSpan idleTimeout, System.Func<System.Boolean> tryEstablishSession, System.Boolean isNewSessionKey)",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"TypeId": "public class Microsoft.AspNetCore.Session.DistributedSession : Microsoft.AspNetCore.Http.ISession",
|
||||
"MemberId": "public .ctor(Microsoft.Extensions.Caching.Distributed.IDistributedCache cache, System.String sessionKey, System.TimeSpan idleTimeout, System.Func<System.Boolean> tryEstablishSession, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.Boolean isNewSessionKey)",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"TypeId": "public class Microsoft.AspNetCore.Session.DistributedSession : Microsoft.AspNetCore.Http.ISession",
|
||||
"MemberId": "public System.Threading.Tasks.Task CommitAsync()",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"TypeId": "public class Microsoft.AspNetCore.Session.DistributedSession : Microsoft.AspNetCore.Http.ISession",
|
||||
"MemberId": "public System.Threading.Tasks.Task LoadAsync()",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"TypeId": "public class Microsoft.AspNetCore.Session.DistributedSessionStore : Microsoft.AspNetCore.Session.ISessionStore",
|
||||
"MemberId": "public Microsoft.AspNetCore.Http.ISession Create(System.String sessionKey, System.TimeSpan idleTimeout, System.Func<System.Boolean> tryEstablishSession, System.Boolean isNewSessionKey)",
|
||||
"Kind": "Removal"
|
||||
},
|
||||
{
|
||||
"TypeId": "public interface Microsoft.AspNetCore.Session.ISessionStore",
|
||||
"MemberId": "Microsoft.AspNetCore.Http.ISession Create(System.String sessionKey, System.TimeSpan idleTimeout, System.TimeSpan ioTimeout, System.Func<System.Boolean> tryEstablishSession, System.Boolean isNewSessionKey)",
|
||||
"Kind": "Addition"
|
||||
}
|
||||
]
|
||||
Loading…
Reference in New Issue