From 07085ca69b15a2103bb1fae47f81a65e54b770c6 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 18 Nov 2015 17:21:03 -0800 Subject: [PATCH] Remove IHttpContextAccessor from TempData This change removes the dependency of TempData on the IHttpContextAccessor by creating an ITempDataDictionaryFactory abstraction. In general, no one will replace the factory, it's just indirection. This allows us to drop our dependency on IHttpContextAccessor, and move it to the functional tests where we specifically depend on it. The bulk of code churn here is to update tests that use TempData. --- .../MvcCoreServiceCollectionExtensions.cs | 1 - .../Controller.cs | 3 +- ...MvcViewFeaturesMvcCoreBuilderExtensions.cs | 13 ++--- .../ViewComponentResult.cs | 3 +- .../ITempDataDictionaryFactory.cs | 25 +++++++++ .../ViewFeatures/PartialViewResultExecutor.cs | 4 +- .../ViewFeatures/SaveTempDataFilter.cs | 12 ++-- .../ViewFeatures/TempDataDictionary.cs | 12 ++-- .../ViewFeatures/TempDataDictionaryFactory.cs | 55 +++++++++++++++++++ .../ViewFeatures/ViewExecutor.cs | 15 ++++- .../ViewFeatures/ViewResultExecutor.cs | 4 +- .../ControllerTest.cs | 10 ++-- .../PartialViewResultTest.cs | 1 + .../Rendering/DefaultTemplatesUtilities.cs | 2 +- .../Rendering/ViewContextTests.cs | 8 ++- .../ViewComponentResultTest.cs | 9 ++- .../ContentViewComponentResultTest.cs | 7 ++- .../HtmlContentViewComponentResultTest.cs | 2 +- .../ViewViewComponentResultTest.cs | 4 +- .../PartialViewResultExecutorTest.cs | 1 + .../ViewFeatures/SaveTempDataFilterTest.cs | 25 +++++++-- .../TempDataDictionaryFactoryTest.cs | 52 ++++++++++++++++++ .../ViewFeatures/TempDataDictionaryTest.cs | 29 ++++------ .../ViewFeatures/ViewExecutorTest.cs | 3 +- .../ViewFeatures/ViewResultExecutorTest.cs | 1 + .../ViewResultTest.cs | 1 + .../ControllersFromServicesWebSite/Startup.cs | 3 + .../RequestServicesWebSite/Startup.cs | 3 + 28 files changed, 240 insertions(+), 68 deletions(-) create mode 100644 src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ITempDataDictionaryFactory.cs create mode 100644 src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/TempDataDictionaryFactory.cs create mode 100644 test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/TempDataDictionaryFactoryTest.cs 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)