diff --git a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs index 02c75ec814..727a7ae229 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs @@ -138,7 +138,6 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs index 0541e13957..db0f726613 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs @@ -260,7 +260,8 @@ namespace Microsoft.AspNet.Mvc { if (_tempData == null) { - _tempData = Resolver?.GetRequiredService(); + var factory = Resolver?.GetRequiredService(); + _tempData = factory?.GetTempData(HttpContext); } return _tempData; diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs index 6348d3db3f..db4ad3ed7b 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs @@ -101,10 +101,7 @@ namespace Microsoft.Extensions.DependencyInjection // services.TryAddTransient(); services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)); - - // DefaultHtmlGenerator is pretty much stateless but depends on IUrlHelper, which is scoped. - // Therefore it too is scoped. - services.TryAddScoped(); + services.TryAddSingleton(); // // JSON Helper @@ -133,12 +130,12 @@ namespace Microsoft.Extensions.DependencyInjection // // Temp Data // - // Holds per-request data so it should be scoped - services.TryAddScoped(); - services.TryAddScoped(); - // This does caching so it should stay singleton services.TryAddSingleton(); + + // These are stateless so their lifetime isn't really important. + services.TryAddSingleton(); + services.TryAddSingleton(); } } } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs index bb04a44ba0..1e7864f38e 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponentResult.cs @@ -88,7 +88,8 @@ namespace Microsoft.AspNet.Mvc var tempData = TempData; if (tempData == null) { - tempData = services.GetRequiredService(); + var factory = services.GetRequiredService(); + tempData = factory.GetTempData(context.HttpContext); } string resolvedContentType = null; diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ITempDataDictionaryFactory.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ITempDataDictionaryFactory.cs new file mode 100644 index 0000000000..a50784ef7b --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ITempDataDictionaryFactory.cs @@ -0,0 +1,25 @@ +// 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.AspNet.Http; + +namespace Microsoft.AspNet.Mvc.ViewFeatures +{ + /// + /// A factory which provides access to an instance + /// for a request. + /// + public interface ITempDataDictionaryFactory + { + /// + /// Gets or creates an instance for the request associated with the + /// given . + /// + /// The . + /// + /// An instance for the request associated with the given + /// . + /// + ITempDataDictionary GetTempData(HttpContext context); + } +} diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/PartialViewResultExecutor.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/PartialViewResultExecutor.cs index 80f70c7982..8acc5d3325 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/PartialViewResultExecutor.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/PartialViewResultExecutor.cs @@ -27,15 +27,17 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// The . /// The . /// The . + /// The . /// The . /// The . public PartialViewResultExecutor( IOptions viewOptions, IHttpResponseStreamWriterFactory writerFactory, ICompositeViewEngine viewEngine, + ITempDataDictionaryFactory tempDataFactory, DiagnosticSource diagnosticSource, ILoggerFactory loggerFactory) - : base(viewOptions, writerFactory, viewEngine, diagnosticSource) + : base(viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticSource) { if (loggerFactory == null) { diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/SaveTempDataFilter.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/SaveTempDataFilter.cs index c0fcf8f32e..0627bf3ec2 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/SaveTempDataFilter.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/SaveTempDataFilter.cs @@ -10,15 +10,15 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// public class SaveTempDataFilter : IResourceFilter, IResultFilter { - private readonly ITempDataDictionary _tempData; + private readonly ITempDataDictionaryFactory _factory; /// /// Creates a new instance of . /// - /// The for the current request. - public SaveTempDataFilter(ITempDataDictionary tempData) + /// The . + public SaveTempDataFilter(ITempDataDictionaryFactory factory) { - _tempData = tempData; + _factory = factory; } /// @@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// public void OnResourceExecuted(ResourceExecutedContext context) { - _tempData.Save(); + _factory.GetTempData(context.HttpContext).Save(); } /// @@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures { if (context.Result is IKeepTempDataResult) { - _tempData.Keep(); + _factory.GetTempData(context.HttpContext).Keep(); } } } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionary.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionary.cs index 1b383c0400..2e499f449d 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionary.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionary.cs @@ -14,16 +14,16 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures private Dictionary _data; private bool _loaded; private readonly ITempDataProvider _provider; - private readonly IHttpContextAccessor _contextAccessor; + private readonly HttpContext _context; private HashSet _initialKeys = new HashSet(StringComparer.OrdinalIgnoreCase); private HashSet _retainedKeys = new HashSet(StringComparer.OrdinalIgnoreCase); /// /// Initializes a new instance of the class. /// - /// The that provides the HttpContext. + /// The . /// The used to Load and Save data. - public TempDataDictionary(IHttpContextAccessor context, ITempDataProvider provider) + public TempDataDictionary(HttpContext context, ITempDataProvider provider) { if (context == null) { @@ -37,7 +37,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures _provider = provider; _loaded = false; - _contextAccessor = context; + _context = context; } public int Count @@ -127,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures return; } - var providerDictionary = _provider.LoadTempData(_contextAccessor.HttpContext); + var providerDictionary = _provider.LoadTempData(_context); _data = (providerDictionary != null) ? new Dictionary(providerDictionary, StringComparer.OrdinalIgnoreCase) : new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -161,7 +161,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures _data.Remove(keys[i]); } - _provider.SaveTempData(_contextAccessor.HttpContext, _data); + _provider.SaveTempData(_context, _data); } /// diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionaryFactory.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionaryFactory.cs new file mode 100644 index 0000000000..797eaa83ac --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionaryFactory.cs @@ -0,0 +1,55 @@ +// 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; + +namespace Microsoft.AspNet.Mvc.ViewFeatures +{ + /// + /// A default implementation of . + /// + public class TempDataDictionaryFactory : ITempDataDictionaryFactory + { + private static readonly object Key = typeof(ITempDataDictionary); + + private readonly ITempDataProvider _provider; + + /// + /// Creates a new . + /// + /// The . + public TempDataDictionaryFactory(ITempDataProvider provider) + { + if (provider == null) + { + throw new ArgumentNullException(nameof(provider)); + } + + _provider = provider; + } + + /// + public ITempDataDictionary GetTempData(HttpContext context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + object obj; + ITempDataDictionary result; + if (context.Items.TryGetValue(Key, out obj)) + { + result = (ITempDataDictionary)obj; + } + else + { + result = new TempDataDictionary(context, _provider); + context.Items.Add(Key, result); + } + + return result; + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs index dce9403185..94ef442327 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs @@ -36,11 +36,13 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// The . /// The . /// The . + /// The . /// The . public ViewExecutor( IOptions viewOptions, IHttpResponseStreamWriterFactory writerFactory, ICompositeViewEngine viewEngine, + ITempDataDictionaryFactory tempDataFactory, DiagnosticSource diagnosticSource) { if (viewOptions == null) @@ -58,6 +60,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures throw new ArgumentNullException(nameof(viewEngine)); } + if (tempDataFactory == null) + { + throw new ArgumentNullException(nameof(tempDataFactory)); + } + if (diagnosticSource == null) { throw new ArgumentNullException(nameof(diagnosticSource)); @@ -66,6 +73,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures ViewOptions = viewOptions.Value; WriterFactory = writerFactory; ViewEngine = viewEngine; + TempDataFactory = tempDataFactory; DiagnosticSource = diagnosticSource; } @@ -74,6 +82,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// protected DiagnosticSource DiagnosticSource { get; } + /// + /// Gets the . + /// + protected ITempDataDictionaryFactory TempDataFactory { get; } + /// /// Gets the default . /// @@ -131,7 +144,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures if (tempData == null) { - tempData = services.GetRequiredService(); + tempData = TempDataFactory.GetTempData(actionContext.HttpContext); } var response = actionContext.HttpContext.Response; diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewResultExecutor.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewResultExecutor.cs index 3cbb44c70c..1b79866a96 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewResultExecutor.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewResultExecutor.cs @@ -25,15 +25,17 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// The . /// The . /// The . + /// The . /// The . /// The . public ViewResultExecutor( IOptions viewOptions, IHttpResponseStreamWriterFactory writerFactory, ICompositeViewEngine viewEngine, + ITempDataDictionaryFactory tempDataFactory, DiagnosticSource diagnosticSource, ILoggerFactory loggerFactory) - : base(viewOptions, writerFactory, viewEngine, diagnosticSource) + : base(viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticSource) { if (loggerFactory == null) { diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs index c6ec89c2d2..b53c21a42d 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ControllerTest.cs @@ -968,7 +968,7 @@ namespace Microsoft.AspNet.Mvc.Test var controller = new TestableController() { ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - TempData = new TempDataDictionary(Mock.Of(), Mock.Of()), + TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of()), }; // Act @@ -989,7 +989,7 @@ namespace Microsoft.AspNet.Mvc.Test var controller = new TestableController() { ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - TempData = new TempDataDictionary(Mock.Of(), Mock.Of()), + TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of()), }; // Act @@ -1010,7 +1010,7 @@ namespace Microsoft.AspNet.Mvc.Test var controller = new TestableController() { ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - TempData = new TempDataDictionary(Mock.Of(), Mock.Of()), + TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of()), }; var model = new object(); @@ -1032,7 +1032,7 @@ namespace Microsoft.AspNet.Mvc.Test var controller = new TestableController() { ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), - TempData = new TempDataDictionary(Mock.Of(), Mock.Of()), + TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of()), }; var model = new object(); @@ -1856,7 +1856,7 @@ namespace Microsoft.AspNet.Mvc.Test var httpContext = new DefaultHttpContext(); var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary()); - var tempData = new TempDataDictionary(Mock.Of(), Mock.Of()); + var tempData = new TempDataDictionary(httpContext, Mock.Of()); var controllerContext = new ControllerContext() { diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/PartialViewResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/PartialViewResultTest.cs index 255d734587..b0ac6bf2f8 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/PartialViewResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/PartialViewResultTest.cs @@ -199,6 +199,7 @@ namespace Microsoft.AspNet.Mvc options, new TestHttpResponseStreamWriterFactory(), new CompositeViewEngine(options), + new TempDataDictionaryFactory(new SessionStateTempDataProvider()), new DiagnosticListener("Microsoft.AspNet"), NullLoggerFactory.Instance); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs index 27f80ea158..7bd01614fd 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs @@ -287,7 +287,7 @@ namespace Microsoft.AspNet.Mvc.Rendering Mock.Of(), viewData, new TempDataDictionary( - new HttpContextAccessor(), + httpContext, Mock.Of()), new StringWriter(), options.HtmlHelperOptions); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/ViewContextTests.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/ViewContextTests.cs index bbe296f5d5..5a9c10e6d3 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/ViewContextTests.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/ViewContextTests.cs @@ -20,12 +20,13 @@ namespace Microsoft.AspNet.Mvc.Rendering public void SettingViewData_AlsoUpdatesViewBag() { // Arrange + var httpContext = new DefaultHttpContext(); var originalViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()); var context = new ViewContext( new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), view: Mock.Of(), viewData: originalViewData, - tempData: new TempDataDictionary(new HttpContextAccessor(), Mock.Of()), + tempData: new TempDataDictionary(httpContext, Mock.Of()), writer: TextWriter.Null, htmlHelperOptions: new HtmlHelperOptions()); var replacementViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()); @@ -47,11 +48,12 @@ namespace Microsoft.AspNet.Mvc.Rendering public void CopyConstructor_CopiesExpectedProperties() { // Arrange + var httpContext = new DefaultHttpContext(); var originalContext = new ViewContext( - new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), + new ActionContext(httpContext, new RouteData(), new ActionDescriptor()), view: Mock.Of(), viewData: new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()), - tempData: new TempDataDictionary(new HttpContextAccessor(), Mock.Of()), + tempData: new TempDataDictionary(httpContext, Mock.Of()), writer: TextWriter.Null, htmlHelperOptions: new HtmlHelperOptions()); var view = Mock.Of(); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs index dd02c9c8e2..75ed4b33b3 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponentResultTest.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc public class ViewComponentResultTest { private readonly ITempDataDictionary _tempDataDictionary = - new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()); + new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider()); [Fact] public async Task ExecuteAsync_ViewComponentResult_AllowsNullViewDataAndTempData() @@ -460,8 +460,7 @@ namespace Microsoft.AspNet.Mvc private IServiceCollection CreateServices(object diagnosticListener, HttpContext context, params ViewComponentDescriptor[] descriptors) { - var httpContext = new HttpContextAccessor() { HttpContext = context }; - var tempDataProvider = new SessionStateTempDataProvider(); + var httpContext = new DefaultHttpContext(); var diagnosticSource = new DiagnosticListener("Microsoft.AspNet"); if (diagnosticListener != null) { @@ -480,8 +479,8 @@ namespace Microsoft.AspNet.Mvc services.AddSingleton(new FixedSetViewComponentDescriptorProvider(descriptors)); services.AddSingleton(); services.AddSingleton(NullLoggerFactory.Instance); - services.AddSingleton(new TempDataDictionary(httpContext, tempDataProvider)); - services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); return services; diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs index 0ee7662aad..bcad673cf9 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ContentViewComponentResultTest.cs @@ -37,13 +37,14 @@ namespace Microsoft.AspNet.Mvc private static ViewComponentContext GetViewComponentContext(IView view, Stream stream) { - var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); + var httpContext = new DefaultHttpContext(); + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider()); var viewContext = new ViewContext( actionContext, view, - viewData, - new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()), + viewData, + new TempDataDictionary(httpContext, new SessionStateTempDataProvider()), TextWriter.Null, new HtmlHelperOptions()); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs index e57a55d89b..866bf7a075 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/HtmlContentViewComponentResultTest.cs @@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc actionContext, view, viewData, - new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()), + new TempDataDictionary(actionContext.HttpContext, new SessionStateTempDataProvider()), TextWriter.Null, new HtmlHelperOptions()); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs index 95e4603207..67b67e17d1 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewComponents/ViewViewComponentResultTest.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc public class ViewViewComponentResultTest { private readonly ITempDataDictionary _tempDataDictionary = - new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()); + new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider()); [Fact] public void Execute_RendersPartialViews() @@ -527,7 +527,7 @@ namespace Microsoft.AspNet.Mvc actionContext, view, viewData, - new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()), + new TempDataDictionary(httpContext, new SessionStateTempDataProvider()), TextWriter.Null, new HtmlHelperOptions()); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/PartialViewResultExecutorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/PartialViewResultExecutorTest.cs index f583d3afe6..d88a768cd1 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/PartialViewResultExecutorTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/PartialViewResultExecutorTest.cs @@ -337,6 +337,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures options, new TestHttpResponseStreamWriterFactory(), new CompositeViewEngine(options), + new TempDataDictionaryFactory(new SessionStateTempDataProvider()), diagnosticSource, NullLoggerFactory.Instance); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/SaveTempDataFilterTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/SaveTempDataFilterTest.cs index 47619fbc45..cc50aa62c9 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/SaveTempDataFilterTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/SaveTempDataFilterTest.cs @@ -1,6 +1,7 @@ // 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.AspNet.Http; using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Filters; @@ -21,7 +22,12 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures .Setup(m => m.Save()) .Verifiable(); - var filter = new SaveTempDataFilter(tempData.Object); + var tempDataFactory = new Mock(MockBehavior.Strict); + tempDataFactory + .Setup(f => f.GetTempData(It.IsAny())) + .Returns(tempData.Object); + + var filter = new SaveTempDataFilter(tempDataFactory.Object); var context = new ResourceExecutedContext( new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), @@ -43,7 +49,12 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures .Setup(m => m.Keep()) .Verifiable(); - var filter = new SaveTempDataFilter(tempData.Object); + var tempDataFactory = new Mock(MockBehavior.Strict); + tempDataFactory + .Setup(f => f.GetTempData(It.IsAny())) + .Returns(tempData.Object); + + var filter = new SaveTempDataFilter(tempDataFactory.Object); var context = new ResultExecutedContext( new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), @@ -63,7 +74,13 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures { // Arrange var tempData = new Mock(MockBehavior.Strict); - var filter = new SaveTempDataFilter(tempData.Object); + + var tempDataFactory = new Mock(MockBehavior.Strict); + tempDataFactory + .Setup(f => f.GetTempData(It.IsAny())) + .Returns(tempData.Object); + + var filter = new SaveTempDataFilter(tempDataFactory.Object); var context = new ResultExecutedContext( new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), @@ -77,4 +94,4 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures // Assert - The mock will throw if we do the wrong thing. } } -} +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryFactoryTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryFactoryTest.cs new file mode 100644 index 0000000000..68e0f9df1e --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryFactoryTest.cs @@ -0,0 +1,52 @@ +// 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.AspNet.Http.Internal; +using Xunit; + +namespace Microsoft.AspNet.Mvc.ViewFeatures +{ + public class TempDataDictionaryFactoryTest + { + [Fact] + public void Factory_CreatesTempData_ForEachHttpContext() + { + // Arrange + var factory = CreateFactory(); + + var context1 = new DefaultHttpContext(); + var context2 = new DefaultHttpContext(); + + var tempData1 = factory.GetTempData(context1); + + // Act + var tempData2 = factory.GetTempData(context2); + + // Assert + Assert.NotSame(tempData1, tempData2); + } + + [Fact] + public void Factory_StoresTempData_InHttpContext() + { + // Arrange + var factory = CreateFactory(); + + var context = new DefaultHttpContext(); + + var tempData1 = factory.GetTempData(context); + + // Act + var tempData2 = factory.GetTempData(context); + + // Assert + Assert.Same(tempData1, tempData2); + } + + private TempDataDictionaryFactory CreateFactory() + { + var provider = new SessionStateTempDataProvider(); + return new TempDataDictionaryFactory(provider); + } + } +} diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryTest.cs index 062a06112d..508e2ff278 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryTest.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void ThrowscdException_OnSettingValue_AndWhenSessionIsNotEnabled() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new SessionStateTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider()); // Act & Assert Assert.Throws(() => @@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void Keep_DoesNotThrowException_WhenDataIsNotLoaded() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new SessionStateTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider()); // Act & Assert tempData.Keep(); @@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void TempData_Load_CreatesEmptyDictionaryIfProviderReturnsNull() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); // Act tempData.Load(); @@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void TempData_Save_RemovesKeysThatWereRead() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); tempData["Foo"] = "Foo"; tempData["Bar"] = "Bar"; @@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void TempData_EnumeratingDictionary_MarksKeysForDeletion() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); tempData["Foo"] = "Foo"; tempData["Bar"] = "Bar"; @@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures [Fact] public void TempData_TryGetValue_MarksKeyForDeletion() { - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); object value; tempData["Foo"] = "Foo"; @@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void TempData_Keep_RetainsAllKeysWhenSavingDictionary() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); tempData["Foo"] = "Foo"; tempData["Bar"] = "Bar"; @@ -121,7 +121,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void TempData_Keep_RetainsSpecificKeysWhenSavingDictionary() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); tempData["Foo"] = "Foo"; tempData["Bar"] = "Bar"; @@ -140,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void TempData_Peek_DoesNotMarkKeyForDeletion() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); tempData["Bar"] = "barValue"; // Act @@ -156,7 +156,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures public void TempData_CompareIsOrdinalIgnoreCase() { // Arrange - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); var item = new object(); // Act @@ -175,7 +175,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures data["Foo"] = "Foo"; data["Bar"] = "Bar"; var provider = new TestTempDataProvider(data); - var tempData = new TempDataDictionary(GetHttpContextAccessor(), provider); + var tempData = new TempDataDictionary(new DefaultHttpContext(), provider); // Act tempData.Load(); @@ -190,7 +190,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures [Fact] public void TempData_RemovalOfKeysAreCaseInsensitive() { - var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); + var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider()); object fooValue; tempData["Foo"] = "Foo"; tempData["Bar"] = "Bar"; @@ -235,10 +235,5 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures { } } - - private static IHttpContextAccessor GetHttpContextAccessor() - { - return new HttpContextAccessor() { HttpContext = new DefaultHttpContext() }; - } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs index 6c09649226..5ad5239d53 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs @@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures private static IServiceProvider GetServiceProvider() { - var httpContext = new HttpContextAccessor() { HttpContext = new DefaultHttpContext() }; + var httpContext = new DefaultHttpContext(); var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton(new EmptyModelMetadataProvider()); var tempDataProvider = new SessionStateTempDataProvider(); @@ -357,6 +357,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures new TestOptionsManager(), new TestHttpResponseStreamWriterFactory(), new Mock(MockBehavior.Strict).Object, + new TempDataDictionaryFactory(new SessionStateTempDataProvider()), diagnosticSource); } } diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewResultExecutorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewResultExecutorTest.cs index 6a1b5842ae..63b0242203 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewResultExecutorTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewResultExecutorTest.cs @@ -333,6 +333,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures options, new TestHttpResponseStreamWriterFactory(), new CompositeViewEngine(options), + new TempDataDictionaryFactory(new SessionStateTempDataProvider()), diagnosticSource, NullLoggerFactory.Instance); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewResultTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewResultTest.cs index 50aa88f9ab..8ba70f2692 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewResultTest.cs @@ -198,6 +198,7 @@ namespace Microsoft.AspNet.Mvc options, new TestHttpResponseStreamWriterFactory(), new CompositeViewEngine(options), + new TempDataDictionaryFactory(new SessionStateTempDataProvider()), new DiagnosticListener("Microsoft.AspNet"), NullLoggerFactory.Instance); diff --git a/test/WebSites/ControllersFromServicesWebSite/Startup.cs b/test/WebSites/ControllersFromServicesWebSite/Startup.cs index 246bd822ed..de5cf9e242 100644 --- a/test/WebSites/ControllersFromServicesWebSite/Startup.cs +++ b/test/WebSites/ControllersFromServicesWebSite/Startup.cs @@ -5,6 +5,8 @@ using System; using System.Reflection; using ControllersFromServicesClassLibrary; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Internal; using Microsoft.Extensions.DependencyInjection; namespace ControllersFromServicesWebSite @@ -21,6 +23,7 @@ namespace ControllersFromServicesWebSite }); services.AddTransient(); + services.AddSingleton(); return services.BuildServiceProvider(); } diff --git a/test/WebSites/RequestServicesWebSite/Startup.cs b/test/WebSites/RequestServicesWebSite/Startup.cs index 2affba1392..1c8bb28120 100644 --- a/test/WebSites/RequestServicesWebSite/Startup.cs +++ b/test/WebSites/RequestServicesWebSite/Startup.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Internal; using Microsoft.Extensions.DependencyInjection; namespace RequestServicesWebSite @@ -14,6 +16,7 @@ namespace RequestServicesWebSite services.AddMvc(); services.AddScoped(); + services.AddSingleton(); } public void Configure(IApplicationBuilder app)