diff --git a/samples/SessionSample/Startup.cs b/samples/SessionSample/Startup.cs index 72132b69bd..0eaa898719 100644 --- a/samples/SessionSample/Startup.cs +++ b/samples/SessionSample/Startup.cs @@ -1,6 +1,10 @@ -using System; +// 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.AspNet.Builder; using Microsoft.AspNet.Http; +using Microsoft.Framework.Caching.Redis; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; @@ -15,16 +19,24 @@ namespace SessionSample public void ConfigureServices(IServiceCollection services) { + // Adds a default in-memory implementation of IDistributedCache services.AddCaching(); + + // Uncomment the following line to use the Redis implementation of IDistributedCache. + // This will override any previously registered IDistributedCache service. + //services.AddTransient(); + services.AddSession(); + + services.ConfigureSession(o => + { + o.IdleTimeout = TimeSpan.FromSeconds(30); + }); } public void Configure(IApplicationBuilder app) { - app.UseSession(o => { - o.IdleTimeout = TimeSpan.FromSeconds(30); }); - // app.UseInMemorySession(); - // app.UseDistributedSession(new RedisCache(new RedisCacheOptions() { Configuration = "localhost" })); + app.UseSession(); app.Map("/session", subApp => { diff --git a/samples/SessionSample/project.json b/samples/SessionSample/project.json index 627614ff39..cf9b17c4b3 100644 --- a/samples/SessionSample/project.json +++ b/samples/SessionSample/project.json @@ -2,10 +2,10 @@ "webroot": "wwwroot", "exclude": "wwwroot/**/*.*", "dependencies": { - "Microsoft.AspNet.Http.Extensions": "1.0.0-*", "Microsoft.AspNet.Server.IIS": "1.0.0-*", - "Microsoft.AspNet.Server.WebListener" : "1.0.0-*", + "Microsoft.AspNet.Server.WebListener": "1.0.0-*", "Microsoft.AspNet.Session": "1.0.0-*", + "Microsoft.Framework.Caching.Memory": "1.0.0-*", "Microsoft.Framework.Caching.Redis": "1.0.0-*", "Microsoft.Framework.Logging.Console": "1.0.0-*" }, diff --git a/src/Microsoft.AspNet.Session/DistributedSession.cs b/src/Microsoft.AspNet.Session/DistributedSession.cs index 20a9514005..36ecb7d49a 100644 --- a/src/Microsoft.AspNet.Session/DistributedSession.cs +++ b/src/Microsoft.AspNet.Session/DistributedSession.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -using Microsoft.AspNet.Http; +using System.Threading.Tasks; using Microsoft.AspNet.Http.Features; using Microsoft.Framework.Caching.Distributed; using Microsoft.Framework.Internal; @@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Session return _store.TryGetValue(new EncodedKey(key), out value); } - public void Set(string key, ArraySegment value) + public void Set(string key, [NotNull] byte[] value) { var encodedKey = new EncodedKey(key); if (encodedKey.KeyBytes.Length > KeyLengthLimit) @@ -64,10 +64,6 @@ namespace Microsoft.AspNet.Session throw new ArgumentOutOfRangeException(nameof(key), string.Format("The key cannot be longer than '{0}' when encoded with UTF-8.", KeyLengthLimit)); } - if (value.Array == null) - { - throw new ArgumentException("The ArraySegment.Array cannot be null.", nameof(value)); - } Load(); if (!_tryEstablishSession()) @@ -75,8 +71,8 @@ namespace Microsoft.AspNet.Session throw new InvalidOperationException("The session cannot be established after the response has started."); } _isModified = true; - byte[] copy = new byte[value.Count]; - Buffer.BlockCopy(value.Array, value.Offset, copy, 0, value.Count); + byte[] copy = new byte[value.Length]; + Buffer.BlockCopy(src: value, srcOffset: 0, dst: copy, dstOffset: 0, count: value.Length); _store[encodedKey] = copy; } @@ -93,12 +89,21 @@ namespace Microsoft.AspNet.Session _store.Clear(); } - // TODO: This should throw if called directly, but most other places it should fail silently (e.g. TryGetValue should just return null). - public void Load() + private void Load() { if (!_loaded) { - var data = _cache.Get(_sessionId); + LoadAsync().GetAwaiter().GetResult(); + } + } + + // TODO: This should throw if called directly, but most other places it should fail silently + // (e.g. TryGetValue should just return null). + public async Task LoadAsync() + { + if (!_loaded) + { + var data = await _cache.GetAsync(_sessionId); if (data != null) { Deserialize(new MemoryStream(data)); @@ -111,11 +116,11 @@ namespace Microsoft.AspNet.Session } } - public void Commit() + public async Task CommitAsync() { if (_isModified) { - var data = _cache.Get(_sessionId); + var data = await _cache.GetAsync(_sessionId); if (_logger.IsEnabled(LogLevel.Information) && data == null) { _logger.LogInformation("Session {0} started", _sessionId); @@ -124,7 +129,7 @@ namespace Microsoft.AspNet.Session var stream = new MemoryStream(); Serialize(stream); - _cache.Set( + await _cache.SetAsync( _sessionId, stream.ToArray(), new DistributedCacheEntryOptions().SetSlidingExpiration(_idleTimeout)); diff --git a/src/Microsoft.AspNet.Session/SessionFactory.cs b/src/Microsoft.AspNet.Session/SessionFactory.cs deleted file mode 100644 index b643f7bac9..0000000000 --- a/src/Microsoft.AspNet.Session/SessionFactory.cs +++ /dev/null @@ -1,37 +0,0 @@ -// 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.AspNet.Http.Features; -using Microsoft.Framework.Internal; - -namespace Microsoft.AspNet.Session -{ - public class SessionFactory : ISessionFactory - { - private readonly string _sessionKey; - private readonly ISessionStore _store; - private readonly TimeSpan _idleTimeout; - private readonly Func _tryEstablishSession; - private readonly bool _isNewSessionKey; - - public SessionFactory([NotNull] string sessionKey, [NotNull] ISessionStore store, TimeSpan idleTimeout, [NotNull] Func tryEstablishSession, bool isNewSessionKey) - { - _sessionKey = sessionKey; - _store = store; - _idleTimeout = idleTimeout; - _tryEstablishSession = tryEstablishSession; - _isNewSessionKey = isNewSessionKey; - } - - public bool IsAvailable - { - get { return _store.IsAvailable; } - } - - public ISession Create() - { - return _store.Create(_sessionKey, _idleTimeout, _tryEstablishSession, _isNewSessionKey); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Session/SessionFeature.cs b/src/Microsoft.AspNet.Session/SessionFeature.cs index 9b8afa2e27..6fba066552 100644 --- a/src/Microsoft.AspNet.Session/SessionFeature.cs +++ b/src/Microsoft.AspNet.Session/SessionFeature.cs @@ -7,8 +7,6 @@ namespace Microsoft.AspNet.Session { public class SessionFeature : ISessionFeature { - public ISessionFactory Factory { get; set; } - public ISession Session { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Session/SessionMiddleware.cs b/src/Microsoft.AspNet.Session/SessionMiddleware.cs index 8a1756604d..3496de13b3 100644 --- a/src/Microsoft.AspNet.Session/SessionMiddleware.cs +++ b/src/Microsoft.AspNet.Session/SessionMiddleware.cs @@ -23,36 +23,19 @@ namespace Microsoft.AspNet.Session private readonly RequestDelegate _next; private readonly SessionOptions _options; private readonly ILogger _logger; + private readonly ISessionStore _sessionStore; public SessionMiddleware( [NotNull] RequestDelegate next, [NotNull] ILoggerFactory loggerFactory, - [NotNull] IEnumerable sessionStore, - [NotNull] IOptions options, - [NotNull] ConfigureOptions configureOptions) + [NotNull] ISessionStore sessionStore, + [NotNull] IOptions options) { _next = next; _logger = loggerFactory.CreateLogger(); - if (configureOptions != null) - { - _options = options.GetNamedOptions(configureOptions.Name); - configureOptions.Configure(_options); - } - else - { - _options = options.Options; - } - - if (_options.Store == null) - { - _options.Store = sessionStore.FirstOrDefault(); - if (_options.Store == null) - { - throw new ArgumentException("ISessionStore must be specified."); - } - } - - _options.Store.Connect(); + _options = options.Options; + _sessionStore = sessionStore; + _sessionStore.Connect(); } public async Task Invoke(HttpContext context) @@ -72,8 +55,7 @@ namespace Microsoft.AspNet.Session } var feature = new SessionFeature(); - feature.Factory = new SessionFactory(sessionKey, _options.Store, _options.IdleTimeout, tryEstablishSession, isNewSessionKey); - feature.Session = feature.Factory.Create(); + feature.Session = _sessionStore.Create(sessionKey, _options.IdleTimeout, tryEstablishSession, isNewSessionKey); context.SetFeature(feature); try @@ -88,7 +70,7 @@ namespace Microsoft.AspNet.Session { try { - feature.Session.Commit(); + await feature.Session.CommitAsync(); } catch (Exception ex) { diff --git a/src/Microsoft.AspNet.Session/SessionMiddlewareExtensions.cs b/src/Microsoft.AspNet.Session/SessionMiddlewareExtensions.cs index 655f0f4b40..89273bc2fc 100644 --- a/src/Microsoft.AspNet.Session/SessionMiddlewareExtensions.cs +++ b/src/Microsoft.AspNet.Session/SessionMiddlewareExtensions.cs @@ -1,45 +1,16 @@ // 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.AspNet.Session; -using Microsoft.Framework.Caching.Distributed; -using Microsoft.Framework.Caching.Memory; -using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Internal; -using Microsoft.Framework.Logging; -using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Builder { public static class SessionMiddlewareExtensions { - public static IApplicationBuilder UseInMemorySession([NotNull] this IApplicationBuilder app, IMemoryCache cache = null, Action configure = null) + public static IApplicationBuilder UseSession([NotNull] this IApplicationBuilder app) { - return app.UseDistributedSession(new LocalCache(cache ?? new MemoryCache(new MemoryCacheOptions())), configure); - } - - public static IApplicationBuilder UseDistributedSession([NotNull] this IApplicationBuilder app, - IDistributedCache cache, Action configure = null) - { - var loggerFactory = app.ApplicationServices.GetRequiredService(); - return app.UseSession(options => - { - options.Store = new DistributedSessionStore(cache, loggerFactory); - if (configure != null) - { - configure(options); - } - }); - } - - public static IApplicationBuilder UseSession([NotNull] this IApplicationBuilder app, Action configure = null) - { - return app.UseMiddleware( - new ConfigureOptions(configure ?? (o => { })) - { - Name = string.Empty - }); + return app.UseMiddleware(); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Session/SessionOptions.cs b/src/Microsoft.AspNet.Session/SessionOptions.cs index 023b5d8e71..f309fb0401 100644 --- a/src/Microsoft.AspNet.Session/SessionOptions.cs +++ b/src/Microsoft.AspNet.Session/SessionOptions.cs @@ -34,10 +34,5 @@ namespace Microsoft.AspNet.Session /// resets the timeout. Note this only applies to the content of the session, not the cookie. /// public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromMinutes(20); - - /// - /// Gets or sets the session storage manager. This overrides any session store passed into the middleware constructor. - /// - public ISessionStore Store { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Session/SessionServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Session/SessionServiceCollectionExtensions.cs index 833d72470e..2fd488820d 100644 --- a/src/Microsoft.AspNet.Session/SessionServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Session/SessionServiceCollectionExtensions.cs @@ -11,19 +11,16 @@ namespace Microsoft.Framework.DependencyInjection { public static IServiceCollection AddSession([NotNull] this IServiceCollection services) { - return services.AddSession(configure: null); + services.AddOptions(); + services.AddTransient(); + return services; } - public static IServiceCollection AddSession([NotNull] this IServiceCollection services, Action configure) + public static void ConfigureSession( + [NotNull] this IServiceCollection services, + [NotNull] Action configure) { - services.AddTransient(); - - if (configure != null) - { - services.Configure(configure); - } - - return services; + services.Configure(configure); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Session/project.json b/src/Microsoft.AspNet.Session/project.json index 105688d976..ae15b0040f 100644 --- a/src/Microsoft.AspNet.Session/project.json +++ b/src/Microsoft.AspNet.Session/project.json @@ -2,10 +2,11 @@ "version": "1.0.0-*", "description": "ASP.NET 5 session state middleware.", "dependencies": { - "Microsoft.AspNet.Http.Extensions": "1.0.0-*", - "Microsoft.Framework.Caching.Memory": "1.0.0-*", + "Microsoft.AspNet.Http.Abstractions": "1.0.0-*", + "Microsoft.Framework.Caching.Abstractions": "1.0.0-*", "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", - "Microsoft.Framework.NotNullAttribute.Sources": { "type": "build", "version": "1.0.0-*" } + "Microsoft.Framework.NotNullAttribute.Sources": { "type": "build", "version": "1.0.0-*" }, + "Microsoft.Framework.OptionsModel": "1.0.0-*" }, "compilationOptions": { "allowUnsafe": true diff --git a/test/Microsoft.AspNet.Session.Tests/SessionTests.cs b/test/Microsoft.AspNet.Session.Tests/SessionTests.cs index 542ac0afd8..58e42c592a 100644 --- a/test/Microsoft.AspNet.Session.Tests/SessionTests.cs +++ b/test/Microsoft.AspNet.Session.Tests/SessionTests.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Session; using Microsoft.AspNet.TestHost; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; @@ -24,14 +25,19 @@ namespace Microsoft.AspNet.Session { using (var server = TestServer.Create(app => { - app.UseInMemorySession(); + app.UseSession(); + app.Run(context => { Assert.Null(context.Session.GetString("NotFound")); return Task.FromResult(0); }); }, - services => services.AddOptions())) + services => + { + services.AddCaching(); + services.AddSession(); + })) { var client = server.CreateClient(); var response = await client.GetAsync(string.Empty); @@ -46,7 +52,7 @@ namespace Microsoft.AspNet.Session { using (var server = TestServer.Create(app => { - app.UseInMemorySession(); + app.UseSession(); app.Run(context => { Assert.Null(context.Session.GetString("Key")); @@ -55,7 +61,11 @@ namespace Microsoft.AspNet.Session return Task.FromResult(0); }); }, - services => services.AddOptions())) + services => + { + services.AddCaching(); + services.AddSession(); + })) { var client = server.CreateClient(); var response = await client.GetAsync(string.Empty); @@ -72,7 +82,7 @@ namespace Microsoft.AspNet.Session { using (var server = TestServer.Create(app => { - app.UseInMemorySession(); + app.UseSession(); app.Run(context => { int? value = context.Session.GetInt32("Key"); @@ -86,7 +96,11 @@ namespace Microsoft.AspNet.Session return context.Response.WriteAsync(value.Value.ToString()); }); }, - services => services.AddOptions())) + services => + { + services.AddCaching(); + services.AddSession(); + })) { var client = server.CreateClient(); var response = await client.GetAsync("first"); @@ -107,7 +121,7 @@ namespace Microsoft.AspNet.Session { using (var server = TestServer.Create(app => { - app.UseInMemorySession(); + app.UseSession(); app.Run(context => { int? value = context.Session.GetInt32("Key"); @@ -131,7 +145,11 @@ namespace Microsoft.AspNet.Session return context.Response.WriteAsync(value.Value.ToString()); }); }, - services => services.AddOptions())) + services => + { + services.AddCaching(); + services.AddSession(); + })) { var client = server.CreateClient(); var response = await client.GetAsync("first"); @@ -151,7 +169,7 @@ namespace Microsoft.AspNet.Session { using (var server = TestServer.Create(app => { - app.UseInMemorySession(); + app.UseSession(); app.Run(context => { int? value = context.Session.GetInt32("Key"); @@ -175,7 +193,11 @@ namespace Microsoft.AspNet.Session return context.Response.WriteAsync(value.Value.ToString()); }); }, - services => services.AddOptions())) + services => + { + services.AddCaching(); + services.AddSession(); + })) { var client = server.CreateClient(); var response = await client.GetAsync("first"); @@ -197,7 +219,7 @@ namespace Microsoft.AspNet.Session var loggerFactory = new TestLoggerFactory(sink, enabled: true); using (var server = TestServer.Create(app => { - app.UseInMemorySession(); + app.UseSession(); app.Run(context => { context.Session.SetString("Key", "Value"); @@ -206,8 +228,9 @@ namespace Microsoft.AspNet.Session }, services => { - services.AddOptions(); services.AddInstance(typeof(ILoggerFactory), loggerFactory); + services.AddCaching(); + services.AddSession(); })) { var client = server.CreateClient(); @@ -226,9 +249,7 @@ namespace Microsoft.AspNet.Session var loggerFactory = new TestLoggerFactory(sink, enabled: true); using (var server = TestServer.Create(app => { - app.UseInMemorySession(configure: o => { - o.IdleTimeout = TimeSpan.FromMilliseconds(30); - }); + app.UseSession(); app.Run(context => { int? value = context.Session.GetInt32("Key"); @@ -248,8 +269,10 @@ namespace Microsoft.AspNet.Session }, services => { - services.AddOptions(); services.AddInstance(typeof(ILoggerFactory), loggerFactory); + services.AddCaching(); + services.AddSession(); + services.ConfigureSession(o => o.IdleTimeout = TimeSpan.FromMilliseconds(30)); })) { var client = server.CreateClient(); diff --git a/test/Microsoft.AspNet.Session.Tests/project.json b/test/Microsoft.AspNet.Session.Tests/project.json index cd31e837c8..658662375c 100644 --- a/test/Microsoft.AspNet.Session.Tests/project.json +++ b/test/Microsoft.AspNet.Session.Tests/project.json @@ -1,14 +1,15 @@ { - "dependencies": { - "Microsoft.AspNet.Session": "1.0.0-*", - "Microsoft.AspNet.TestHost": "1.0.0-*", - "Microsoft.Framework.Logging.Testing": "1.0.0-*", - "xunit.runner.aspnet": "2.0.0-aspnet-*" - }, - "commands": { - "test": "xunit.runner.aspnet" - }, - "frameworks": { - "dnx451": {} - } + "dependencies": { + "Microsoft.AspNet.Session": "1.0.0-*", + "Microsoft.AspNet.TestHost": "1.0.0-*", + "Microsoft.Framework.Caching.Memory": "1.0.0-*", + "Microsoft.Framework.Logging.Testing": "1.0.0-*", + "xunit.runner.aspnet": "2.0.0-aspnet-*" + }, + "commands": { + "test": "xunit.runner.aspnet" + }, + "frameworks": { + "dnx451": { } + } }