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.
This commit is contained in:
Ryan Nowak 2015-11-18 17:21:03 -08:00
parent 70bdb6eb3e
commit 07085ca69b
28 changed files with 240 additions and 68 deletions

View File

@ -138,7 +138,6 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<MvcMarkerService, MvcMarkerService>(); services.TryAddSingleton<MvcMarkerService, MvcMarkerService>();
services.TryAddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>(); services.TryAddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>(); services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IUrlHelper, UrlHelper>(); services.TryAddSingleton<IUrlHelper, UrlHelper>();
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>(); services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>(); services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();

View File

@ -260,7 +260,8 @@ namespace Microsoft.AspNet.Mvc
{ {
if (_tempData == null) if (_tempData == null)
{ {
_tempData = Resolver?.GetRequiredService<ITempDataDictionary>(); var factory = Resolver?.GetRequiredService<ITempDataDictionaryFactory>();
_tempData = factory?.GetTempData(HttpContext);
} }
return _tempData; return _tempData;

View File

@ -101,10 +101,7 @@ namespace Microsoft.Extensions.DependencyInjection
// //
services.TryAddTransient<IHtmlHelper, HtmlHelper>(); services.TryAddTransient<IHtmlHelper, HtmlHelper>();
services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)); services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>));
services.TryAddSingleton<IHtmlGenerator, DefaultHtmlGenerator>();
// DefaultHtmlGenerator is pretty much stateless but depends on IUrlHelper, which is scoped.
// Therefore it too is scoped.
services.TryAddScoped<IHtmlGenerator, DefaultHtmlGenerator>();
// //
// JSON Helper // JSON Helper
@ -133,12 +130,12 @@ namespace Microsoft.Extensions.DependencyInjection
// //
// Temp Data // Temp Data
// //
// Holds per-request data so it should be scoped
services.TryAddScoped<ITempDataDictionary, TempDataDictionary>();
services.TryAddScoped<SaveTempDataFilter>();
// This does caching so it should stay singleton // This does caching so it should stay singleton
services.TryAddSingleton<ITempDataProvider, SessionStateTempDataProvider>(); services.TryAddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
// These are stateless so their lifetime isn't really important.
services.TryAddSingleton<ITempDataDictionaryFactory, TempDataDictionaryFactory>();
services.TryAddSingleton<SaveTempDataFilter>();
} }
} }
} }

View File

@ -88,7 +88,8 @@ namespace Microsoft.AspNet.Mvc
var tempData = TempData; var tempData = TempData;
if (tempData == null) if (tempData == null)
{ {
tempData = services.GetRequiredService<ITempDataDictionary>(); var factory = services.GetRequiredService<ITempDataDictionaryFactory>();
tempData = factory.GetTempData(context.HttpContext);
} }
string resolvedContentType = null; string resolvedContentType = null;

View File

@ -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
{
/// <summary>
/// A factory which provides access to an <see cref="ITempDataDictionary"/> instance
/// for a request.
/// </summary>
public interface ITempDataDictionaryFactory
{
/// <summary>
/// Gets or creates an <see cref="ITempDataDictionary"/> instance for the request associated with the
/// given <paramref name="context"/>.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/>.</param>
/// <returns>
/// An <see cref="ITempDataDictionary"/> instance for the request associated with the given
/// <paramref name="context"/>.
/// </returns>
ITempDataDictionary GetTempData(HttpContext context);
}
}

View File

@ -27,15 +27,17 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// <param name="viewOptions">The <see cref="IOptions{MvcViewOptions}"/>.</param> /// <param name="viewOptions">The <see cref="IOptions{MvcViewOptions}"/>.</param>
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param> /// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
/// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param> /// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param>
/// <param name="tempDataFactory">The <see cref="ITempDataDictionaryFactory"/>.</param>
/// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param> /// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public PartialViewResultExecutor( public PartialViewResultExecutor(
IOptions<MvcViewOptions> viewOptions, IOptions<MvcViewOptions> viewOptions,
IHttpResponseStreamWriterFactory writerFactory, IHttpResponseStreamWriterFactory writerFactory,
ICompositeViewEngine viewEngine, ICompositeViewEngine viewEngine,
ITempDataDictionaryFactory tempDataFactory,
DiagnosticSource diagnosticSource, DiagnosticSource diagnosticSource,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
: base(viewOptions, writerFactory, viewEngine, diagnosticSource) : base(viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticSource)
{ {
if (loggerFactory == null) if (loggerFactory == null)
{ {

View File

@ -10,15 +10,15 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// </summary> /// </summary>
public class SaveTempDataFilter : IResourceFilter, IResultFilter public class SaveTempDataFilter : IResourceFilter, IResultFilter
{ {
private readonly ITempDataDictionary _tempData; private readonly ITempDataDictionaryFactory _factory;
/// <summary> /// <summary>
/// Creates a new instance of <see cref="SaveTempDataFilter"/>. /// Creates a new instance of <see cref="SaveTempDataFilter"/>.
/// </summary> /// </summary>
/// <param name="tempData">The <see cref="ITempDataDictionary"/> for the current request.</param> /// <param name="factory">The <see cref="ITempDataDictionaryFactory"/>.</param>
public SaveTempDataFilter(ITempDataDictionary tempData) public SaveTempDataFilter(ITempDataDictionaryFactory factory)
{ {
_tempData = tempData; _factory = factory;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// <inheritdoc /> /// <inheritdoc />
public void OnResourceExecuted(ResourceExecutedContext context) public void OnResourceExecuted(ResourceExecutedContext context)
{ {
_tempData.Save(); _factory.GetTempData(context.HttpContext).Save();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
{ {
if (context.Result is IKeepTempDataResult) if (context.Result is IKeepTempDataResult)
{ {
_tempData.Keep(); _factory.GetTempData(context.HttpContext).Keep();
} }
} }
} }

View File

@ -14,16 +14,16 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
private Dictionary<string, object> _data; private Dictionary<string, object> _data;
private bool _loaded; private bool _loaded;
private readonly ITempDataProvider _provider; private readonly ITempDataProvider _provider;
private readonly IHttpContextAccessor _contextAccessor; private readonly HttpContext _context;
private HashSet<string> _initialKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private HashSet<string> _initialKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private HashSet<string> _retainedKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private HashSet<string> _retainedKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TempDataDictionary"/> class. /// Initializes a new instance of the <see cref="TempDataDictionary"/> class.
/// </summary> /// </summary>
/// <param name="context">The <see cref="IHttpContextAccessor"/> that provides the HttpContext.</param> /// <param name="context">The <see cref="HttpContext"/>.</param>
/// <param name="provider">The <see cref="ITempDataProvider"/> used to Load and Save data.</param> /// <param name="provider">The <see cref="ITempDataProvider"/> used to Load and Save data.</param>
public TempDataDictionary(IHttpContextAccessor context, ITempDataProvider provider) public TempDataDictionary(HttpContext context, ITempDataProvider provider)
{ {
if (context == null) if (context == null)
{ {
@ -37,7 +37,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
_provider = provider; _provider = provider;
_loaded = false; _loaded = false;
_contextAccessor = context; _context = context;
} }
public int Count public int Count
@ -127,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
return; return;
} }
var providerDictionary = _provider.LoadTempData(_contextAccessor.HttpContext); var providerDictionary = _provider.LoadTempData(_context);
_data = (providerDictionary != null) _data = (providerDictionary != null)
? new Dictionary<string, object>(providerDictionary, StringComparer.OrdinalIgnoreCase) ? new Dictionary<string, object>(providerDictionary, StringComparer.OrdinalIgnoreCase)
: new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); : new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
@ -161,7 +161,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
_data.Remove(keys[i]); _data.Remove(keys[i]);
} }
_provider.SaveTempData(_contextAccessor.HttpContext, _data); _provider.SaveTempData(_context, _data);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -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
{
/// <summary>
/// A default implementation of <see cref="ITempDataDictionaryFactory"/>.
/// </summary>
public class TempDataDictionaryFactory : ITempDataDictionaryFactory
{
private static readonly object Key = typeof(ITempDataDictionary);
private readonly ITempDataProvider _provider;
/// <summary>
/// Creates a new <see cref="TempDataDictionaryFactory"/>.
/// </summary>
/// <param name="provider">The <see cref="ITempDataProvider"/>.</param>
public TempDataDictionaryFactory(ITempDataProvider provider)
{
if (provider == null)
{
throw new ArgumentNullException(nameof(provider));
}
_provider = provider;
}
/// <inheritdoc />
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;
}
}
}

View File

@ -36,11 +36,13 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// <param name="viewOptions">The <see cref="IOptions{MvcViewOptions}"/>.</param> /// <param name="viewOptions">The <see cref="IOptions{MvcViewOptions}"/>.</param>
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param> /// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
/// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param> /// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param>
/// <param name="tempDataFactory">The <see cref="ITempDataDictionaryFactory"/>.</param>
/// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param> /// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param>
public ViewExecutor( public ViewExecutor(
IOptions<MvcViewOptions> viewOptions, IOptions<MvcViewOptions> viewOptions,
IHttpResponseStreamWriterFactory writerFactory, IHttpResponseStreamWriterFactory writerFactory,
ICompositeViewEngine viewEngine, ICompositeViewEngine viewEngine,
ITempDataDictionaryFactory tempDataFactory,
DiagnosticSource diagnosticSource) DiagnosticSource diagnosticSource)
{ {
if (viewOptions == null) if (viewOptions == null)
@ -58,6 +60,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
throw new ArgumentNullException(nameof(viewEngine)); throw new ArgumentNullException(nameof(viewEngine));
} }
if (tempDataFactory == null)
{
throw new ArgumentNullException(nameof(tempDataFactory));
}
if (diagnosticSource == null) if (diagnosticSource == null)
{ {
throw new ArgumentNullException(nameof(diagnosticSource)); throw new ArgumentNullException(nameof(diagnosticSource));
@ -66,6 +73,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
ViewOptions = viewOptions.Value; ViewOptions = viewOptions.Value;
WriterFactory = writerFactory; WriterFactory = writerFactory;
ViewEngine = viewEngine; ViewEngine = viewEngine;
TempDataFactory = tempDataFactory;
DiagnosticSource = diagnosticSource; DiagnosticSource = diagnosticSource;
} }
@ -74,6 +82,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// </summary> /// </summary>
protected DiagnosticSource DiagnosticSource { get; } protected DiagnosticSource DiagnosticSource { get; }
/// <summary>
/// Gets the <see cref="ITempDataDictionaryFactory"/>.
/// </summary>
protected ITempDataDictionaryFactory TempDataFactory { get; }
/// <summary> /// <summary>
/// Gets the default <see cref="IViewEngine"/>. /// Gets the default <see cref="IViewEngine"/>.
/// </summary> /// </summary>
@ -131,7 +144,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
if (tempData == null) if (tempData == null)
{ {
tempData = services.GetRequiredService<ITempDataDictionary>(); tempData = TempDataFactory.GetTempData(actionContext.HttpContext);
} }
var response = actionContext.HttpContext.Response; var response = actionContext.HttpContext.Response;

View File

@ -25,15 +25,17 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// <param name="viewOptions">The <see cref="IOptions{MvcViewOptions}"/>.</param> /// <param name="viewOptions">The <see cref="IOptions{MvcViewOptions}"/>.</param>
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param> /// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
/// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param> /// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param>
/// <param name="tempDataFactory">The <see cref="ITempDataDictionaryFactory"/>.</param>
/// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param> /// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public ViewResultExecutor( public ViewResultExecutor(
IOptions<MvcViewOptions> viewOptions, IOptions<MvcViewOptions> viewOptions,
IHttpResponseStreamWriterFactory writerFactory, IHttpResponseStreamWriterFactory writerFactory,
ICompositeViewEngine viewEngine, ICompositeViewEngine viewEngine,
ITempDataDictionaryFactory tempDataFactory,
DiagnosticSource diagnosticSource, DiagnosticSource diagnosticSource,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
: base(viewOptions, writerFactory, viewEngine, diagnosticSource) : base(viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticSource)
{ {
if (loggerFactory == null) if (loggerFactory == null)
{ {

View File

@ -968,7 +968,7 @@ namespace Microsoft.AspNet.Mvc.Test
var controller = new TestableController() var controller = new TestableController()
{ {
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()), TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of<ITempDataProvider>()),
}; };
// Act // Act
@ -989,7 +989,7 @@ namespace Microsoft.AspNet.Mvc.Test
var controller = new TestableController() var controller = new TestableController()
{ {
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()), TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of<ITempDataProvider>()),
}; };
// Act // Act
@ -1010,7 +1010,7 @@ namespace Microsoft.AspNet.Mvc.Test
var controller = new TestableController() var controller = new TestableController()
{ {
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()), TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of<ITempDataProvider>()),
}; };
var model = new object(); var model = new object();
@ -1032,7 +1032,7 @@ namespace Microsoft.AspNet.Mvc.Test
var controller = new TestableController() var controller = new TestableController()
{ {
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()), ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()), TempData = new TempDataDictionary(new DefaultHttpContext(), Mock.Of<ITempDataProvider>()),
}; };
var model = new object(); var model = new object();
@ -1856,7 +1856,7 @@ namespace Microsoft.AspNet.Mvc.Test
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary()); var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
var tempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()); var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
var controllerContext = new ControllerContext() var controllerContext = new ControllerContext()
{ {

View File

@ -199,6 +199,7 @@ namespace Microsoft.AspNet.Mvc
options, options,
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
new CompositeViewEngine(options), new CompositeViewEngine(options),
new TempDataDictionaryFactory(new SessionStateTempDataProvider()),
new DiagnosticListener("Microsoft.AspNet"), new DiagnosticListener("Microsoft.AspNet"),
NullLoggerFactory.Instance); NullLoggerFactory.Instance);

View File

@ -287,7 +287,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
Mock.Of<IView>(), Mock.Of<IView>(),
viewData, viewData,
new TempDataDictionary( new TempDataDictionary(
new HttpContextAccessor(), httpContext,
Mock.Of<ITempDataProvider>()), Mock.Of<ITempDataProvider>()),
new StringWriter(), new StringWriter(),
options.HtmlHelperOptions); options.HtmlHelperOptions);

View File

@ -20,12 +20,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
public void SettingViewData_AlsoUpdatesViewBag() public void SettingViewData_AlsoUpdatesViewBag()
{ {
// Arrange // Arrange
var httpContext = new DefaultHttpContext();
var originalViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()); var originalViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider());
var context = new ViewContext( var context = new ViewContext(
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
view: Mock.Of<IView>(), view: Mock.Of<IView>(),
viewData: originalViewData, viewData: originalViewData,
tempData: new TempDataDictionary(new HttpContextAccessor(), Mock.Of<ITempDataProvider>()), tempData: new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>()),
writer: TextWriter.Null, writer: TextWriter.Null,
htmlHelperOptions: new HtmlHelperOptions()); htmlHelperOptions: new HtmlHelperOptions());
var replacementViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()); var replacementViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider());
@ -47,11 +48,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
public void CopyConstructor_CopiesExpectedProperties() public void CopyConstructor_CopiesExpectedProperties()
{ {
// Arrange // Arrange
var httpContext = new DefaultHttpContext();
var originalContext = new ViewContext( var originalContext = new ViewContext(
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), new ActionContext(httpContext, new RouteData(), new ActionDescriptor()),
view: Mock.Of<IView>(), view: Mock.Of<IView>(),
viewData: new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()), viewData: new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()),
tempData: new TempDataDictionary(new HttpContextAccessor(), Mock.Of<ITempDataProvider>()), tempData: new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>()),
writer: TextWriter.Null, writer: TextWriter.Null,
htmlHelperOptions: new HtmlHelperOptions()); htmlHelperOptions: new HtmlHelperOptions());
var view = Mock.Of<IView>(); var view = Mock.Of<IView>();

View File

@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc
public class ViewComponentResultTest public class ViewComponentResultTest
{ {
private readonly ITempDataDictionary _tempDataDictionary = private readonly ITempDataDictionary _tempDataDictionary =
new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()); new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider());
[Fact] [Fact]
public async Task ExecuteAsync_ViewComponentResult_AllowsNullViewDataAndTempData() public async Task ExecuteAsync_ViewComponentResult_AllowsNullViewDataAndTempData()
@ -460,8 +460,7 @@ namespace Microsoft.AspNet.Mvc
private IServiceCollection CreateServices(object diagnosticListener, HttpContext context, params ViewComponentDescriptor[] descriptors) private IServiceCollection CreateServices(object diagnosticListener, HttpContext context, params ViewComponentDescriptor[] descriptors)
{ {
var httpContext = new HttpContextAccessor() { HttpContext = context }; var httpContext = new DefaultHttpContext();
var tempDataProvider = new SessionStateTempDataProvider();
var diagnosticSource = new DiagnosticListener("Microsoft.AspNet"); var diagnosticSource = new DiagnosticListener("Microsoft.AspNet");
if (diagnosticListener != null) if (diagnosticListener != null)
{ {
@ -480,8 +479,8 @@ namespace Microsoft.AspNet.Mvc
services.AddSingleton<IViewComponentDescriptorProvider>(new FixedSetViewComponentDescriptorProvider(descriptors)); services.AddSingleton<IViewComponentDescriptorProvider>(new FixedSetViewComponentDescriptorProvider(descriptors));
services.AddSingleton<IModelMetadataProvider, EmptyModelMetadataProvider>(); services.AddSingleton<IModelMetadataProvider, EmptyModelMetadataProvider>();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance); services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
services.AddSingleton<ITempDataDictionary>(new TempDataDictionary(httpContext, tempDataProvider)); services.AddSingleton<ITempDataDictionaryFactory, TempDataDictionaryFactory>();
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
services.AddSingleton<HtmlEncoder, HtmlTestEncoder>(); services.AddSingleton<HtmlEncoder, HtmlTestEncoder>();
return services; return services;

View File

@ -37,13 +37,14 @@ namespace Microsoft.AspNet.Mvc
private static ViewComponentContext GetViewComponentContext(IView view, Stream stream) 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 viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
var viewContext = new ViewContext( var viewContext = new ViewContext(
actionContext, actionContext,
view, view,
viewData, viewData,
new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()), new TempDataDictionary(httpContext, new SessionStateTempDataProvider()),
TextWriter.Null, TextWriter.Null,
new HtmlHelperOptions()); new HtmlHelperOptions());

View File

@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc
actionContext, actionContext,
view, view,
viewData, viewData,
new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()), new TempDataDictionary(actionContext.HttpContext, new SessionStateTempDataProvider()),
TextWriter.Null, TextWriter.Null,
new HtmlHelperOptions()); new HtmlHelperOptions());

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc
public class ViewViewComponentResultTest public class ViewViewComponentResultTest
{ {
private readonly ITempDataDictionary _tempDataDictionary = private readonly ITempDataDictionary _tempDataDictionary =
new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()); new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider());
[Fact] [Fact]
public void Execute_RendersPartialViews() public void Execute_RendersPartialViews()
@ -527,7 +527,7 @@ namespace Microsoft.AspNet.Mvc
actionContext, actionContext,
view, view,
viewData, viewData,
new TempDataDictionary(new HttpContextAccessor(), new SessionStateTempDataProvider()), new TempDataDictionary(httpContext, new SessionStateTempDataProvider()),
TextWriter.Null, TextWriter.Null,
new HtmlHelperOptions()); new HtmlHelperOptions());

View File

@ -337,6 +337,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
options, options,
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
new CompositeViewEngine(options), new CompositeViewEngine(options),
new TempDataDictionaryFactory(new SessionStateTempDataProvider()),
diagnosticSource, diagnosticSource,
NullLoggerFactory.Instance); NullLoggerFactory.Instance);

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Filters;
@ -21,7 +22,12 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
.Setup(m => m.Save()) .Setup(m => m.Save())
.Verifiable(); .Verifiable();
var filter = new SaveTempDataFilter(tempData.Object); var tempDataFactory = new Mock<ITempDataDictionaryFactory>(MockBehavior.Strict);
tempDataFactory
.Setup(f => f.GetTempData(It.IsAny<HttpContext>()))
.Returns(tempData.Object);
var filter = new SaveTempDataFilter(tempDataFactory.Object);
var context = new ResourceExecutedContext( var context = new ResourceExecutedContext(
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
@ -43,7 +49,12 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
.Setup(m => m.Keep()) .Setup(m => m.Keep())
.Verifiable(); .Verifiable();
var filter = new SaveTempDataFilter(tempData.Object); var tempDataFactory = new Mock<ITempDataDictionaryFactory>(MockBehavior.Strict);
tempDataFactory
.Setup(f => f.GetTempData(It.IsAny<HttpContext>()))
.Returns(tempData.Object);
var filter = new SaveTempDataFilter(tempDataFactory.Object);
var context = new ResultExecutedContext( var context = new ResultExecutedContext(
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
@ -63,7 +74,13 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
{ {
// Arrange // Arrange
var tempData = new Mock<ITempDataDictionary>(MockBehavior.Strict); var tempData = new Mock<ITempDataDictionary>(MockBehavior.Strict);
var filter = new SaveTempDataFilter(tempData.Object);
var tempDataFactory = new Mock<ITempDataDictionaryFactory>(MockBehavior.Strict);
tempDataFactory
.Setup(f => f.GetTempData(It.IsAny<HttpContext>()))
.Returns(tempData.Object);
var filter = new SaveTempDataFilter(tempDataFactory.Object);
var context = new ResultExecutedContext( var context = new ResultExecutedContext(
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()), 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. // Assert - The mock will throw if we do the wrong thing.
} }
} }
} }

View File

@ -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);
}
}
}

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void ThrowscdException_OnSettingValue_AndWhenSessionIsNotEnabled() public void ThrowscdException_OnSettingValue_AndWhenSessionIsNotEnabled()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new SessionStateTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider());
// Act & Assert // Act & Assert
Assert.Throws<InvalidOperationException>(() => Assert.Throws<InvalidOperationException>(() =>
@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void Keep_DoesNotThrowException_WhenDataIsNotLoaded() public void Keep_DoesNotThrowException_WhenDataIsNotLoaded()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new SessionStateTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider());
// Act & Assert // Act & Assert
tempData.Keep(); tempData.Keep();
@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void TempData_Load_CreatesEmptyDictionaryIfProviderReturnsNull() public void TempData_Load_CreatesEmptyDictionaryIfProviderReturnsNull()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
// Act // Act
tempData.Load(); tempData.Load();
@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void TempData_Save_RemovesKeysThatWereRead() public void TempData_Save_RemovesKeysThatWereRead()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
tempData["Foo"] = "Foo"; tempData["Foo"] = "Foo";
tempData["Bar"] = "Bar"; tempData["Bar"] = "Bar";
@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void TempData_EnumeratingDictionary_MarksKeysForDeletion() public void TempData_EnumeratingDictionary_MarksKeysForDeletion()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
tempData["Foo"] = "Foo"; tempData["Foo"] = "Foo";
tempData["Bar"] = "Bar"; tempData["Bar"] = "Bar";
@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
[Fact] [Fact]
public void TempData_TryGetValue_MarksKeyForDeletion() public void TempData_TryGetValue_MarksKeyForDeletion()
{ {
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
object value; object value;
tempData["Foo"] = "Foo"; tempData["Foo"] = "Foo";
@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void TempData_Keep_RetainsAllKeysWhenSavingDictionary() public void TempData_Keep_RetainsAllKeysWhenSavingDictionary()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
tempData["Foo"] = "Foo"; tempData["Foo"] = "Foo";
tempData["Bar"] = "Bar"; tempData["Bar"] = "Bar";
@ -121,7 +121,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void TempData_Keep_RetainsSpecificKeysWhenSavingDictionary() public void TempData_Keep_RetainsSpecificKeysWhenSavingDictionary()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
tempData["Foo"] = "Foo"; tempData["Foo"] = "Foo";
tempData["Bar"] = "Bar"; tempData["Bar"] = "Bar";
@ -140,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void TempData_Peek_DoesNotMarkKeyForDeletion() public void TempData_Peek_DoesNotMarkKeyForDeletion()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
tempData["Bar"] = "barValue"; tempData["Bar"] = "barValue";
// Act // Act
@ -156,7 +156,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public void TempData_CompareIsOrdinalIgnoreCase() public void TempData_CompareIsOrdinalIgnoreCase()
{ {
// Arrange // Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
var item = new object(); var item = new object();
// Act // Act
@ -175,7 +175,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
data["Foo"] = "Foo"; data["Foo"] = "Foo";
data["Bar"] = "Bar"; data["Bar"] = "Bar";
var provider = new TestTempDataProvider(data); var provider = new TestTempDataProvider(data);
var tempData = new TempDataDictionary(GetHttpContextAccessor(), provider); var tempData = new TempDataDictionary(new DefaultHttpContext(), provider);
// Act // Act
tempData.Load(); tempData.Load();
@ -190,7 +190,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
[Fact] [Fact]
public void TempData_RemovalOfKeysAreCaseInsensitive() public void TempData_RemovalOfKeysAreCaseInsensitive()
{ {
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider()); var tempData = new TempDataDictionary(new DefaultHttpContext(), new NullTempDataProvider());
object fooValue; object fooValue;
tempData["Foo"] = "Foo"; tempData["Foo"] = "Foo";
tempData["Bar"] = "Bar"; tempData["Bar"] = "Bar";
@ -235,10 +235,5 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
{ {
} }
} }
private static IHttpContextAccessor GetHttpContextAccessor()
{
return new HttpContextAccessor() { HttpContext = new DefaultHttpContext() };
}
} }
} }

View File

@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
private static IServiceProvider GetServiceProvider() private static IServiceProvider GetServiceProvider()
{ {
var httpContext = new HttpContextAccessor() { HttpContext = new DefaultHttpContext() }; var httpContext = new DefaultHttpContext();
var serviceCollection = new ServiceCollection(); var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IModelMetadataProvider>(new EmptyModelMetadataProvider()); serviceCollection.AddSingleton<IModelMetadataProvider>(new EmptyModelMetadataProvider());
var tempDataProvider = new SessionStateTempDataProvider(); var tempDataProvider = new SessionStateTempDataProvider();
@ -357,6 +357,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
new TestOptionsManager<MvcViewOptions>(), new TestOptionsManager<MvcViewOptions>(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
new Mock<ICompositeViewEngine>(MockBehavior.Strict).Object, new Mock<ICompositeViewEngine>(MockBehavior.Strict).Object,
new TempDataDictionaryFactory(new SessionStateTempDataProvider()),
diagnosticSource); diagnosticSource);
} }
} }

View File

@ -333,6 +333,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
options, options,
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
new CompositeViewEngine(options), new CompositeViewEngine(options),
new TempDataDictionaryFactory(new SessionStateTempDataProvider()),
diagnosticSource, diagnosticSource,
NullLoggerFactory.Instance); NullLoggerFactory.Instance);

View File

@ -198,6 +198,7 @@ namespace Microsoft.AspNet.Mvc
options, options,
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
new CompositeViewEngine(options), new CompositeViewEngine(options),
new TempDataDictionaryFactory(new SessionStateTempDataProvider()),
new DiagnosticListener("Microsoft.AspNet"), new DiagnosticListener("Microsoft.AspNet"),
NullLoggerFactory.Instance); NullLoggerFactory.Instance);

View File

@ -5,6 +5,8 @@ using System;
using System.Reflection; using System.Reflection;
using ControllersFromServicesClassLibrary; using ControllersFromServicesClassLibrary;
using Microsoft.AspNet.Builder; using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace ControllersFromServicesWebSite namespace ControllersFromServicesWebSite
@ -21,6 +23,7 @@ namespace ControllersFromServicesWebSite
}); });
services.AddTransient<QueryValueService>(); services.AddTransient<QueryValueService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
return services.BuildServiceProvider(); return services.BuildServiceProvider();
} }

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace RequestServicesWebSite namespace RequestServicesWebSite
@ -14,6 +16,7 @@ namespace RequestServicesWebSite
services.AddMvc(); services.AddMvc();
services.AddScoped<RequestIdService>(); services.AddScoped<RequestIdService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
} }
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app)