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<ITypeActivatorCache, DefaultTypeActivatorCache>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IUrlHelper, UrlHelper>();
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();

View File

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

View File

@ -101,10 +101,7 @@ namespace Microsoft.Extensions.DependencyInjection
//
services.TryAddTransient<IHtmlHelper, HtmlHelper>();
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<IHtmlGenerator, DefaultHtmlGenerator>();
services.TryAddSingleton<IHtmlGenerator, DefaultHtmlGenerator>();
//
// JSON Helper
@ -133,12 +130,12 @@ namespace Microsoft.Extensions.DependencyInjection
//
// 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
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;
if (tempData == null)
{
tempData = services.GetRequiredService<ITempDataDictionary>();
var factory = services.GetRequiredService<ITempDataDictionaryFactory>();
tempData = factory.GetTempData(context.HttpContext);
}
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="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</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="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public PartialViewResultExecutor(
IOptions<MvcViewOptions> 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)
{

View File

@ -10,15 +10,15 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// </summary>
public class SaveTempDataFilter : IResourceFilter, IResultFilter
{
private readonly ITempDataDictionary _tempData;
private readonly ITempDataDictionaryFactory _factory;
/// <summary>
/// Creates a new instance of <see cref="SaveTempDataFilter"/>.
/// </summary>
/// <param name="tempData">The <see cref="ITempDataDictionary"/> for the current request.</param>
public SaveTempDataFilter(ITempDataDictionary tempData)
/// <param name="factory">The <see cref="ITempDataDictionaryFactory"/>.</param>
public SaveTempDataFilter(ITempDataDictionaryFactory factory)
{
_tempData = tempData;
_factory = factory;
}
/// <inheritdoc />
@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// <inheritdoc />
public void OnResourceExecuted(ResourceExecutedContext context)
{
_tempData.Save();
_factory.GetTempData(context.HttpContext).Save();
}
/// <inheritdoc />
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
{
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 bool _loaded;
private readonly ITempDataProvider _provider;
private readonly IHttpContextAccessor _contextAccessor;
private readonly HttpContext _context;
private HashSet<string> _initialKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private HashSet<string> _retainedKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Initializes a new instance of the <see cref="TempDataDictionary"/> class.
/// </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>
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<string, object>(providerDictionary, StringComparer.OrdinalIgnoreCase)
: new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
@ -161,7 +161,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
_data.Remove(keys[i]);
}
_provider.SaveTempData(_contextAccessor.HttpContext, _data);
_provider.SaveTempData(_context, _data);
}
/// <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="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</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>
public ViewExecutor(
IOptions<MvcViewOptions> 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
/// </summary>
protected DiagnosticSource DiagnosticSource { get; }
/// <summary>
/// Gets the <see cref="ITempDataDictionaryFactory"/>.
/// </summary>
protected ITempDataDictionaryFactory TempDataFactory { get; }
/// <summary>
/// Gets the default <see cref="IViewEngine"/>.
/// </summary>
@ -131,7 +144,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
if (tempData == null)
{
tempData = services.GetRequiredService<ITempDataDictionary>();
tempData = TempDataFactory.GetTempData(actionContext.HttpContext);
}
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="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</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="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public ViewResultExecutor(
IOptions<MvcViewOptions> 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)
{

View File

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

View File

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

View File

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

View File

@ -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<IView>(),
viewData: originalViewData,
tempData: new TempDataDictionary(new HttpContextAccessor(), Mock.Of<ITempDataProvider>()),
tempData: new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>()),
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<IView>(),
viewData: new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider()),
tempData: new TempDataDictionary(new HttpContextAccessor(), Mock.Of<ITempDataProvider>()),
tempData: new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>()),
writer: TextWriter.Null,
htmlHelperOptions: new HtmlHelperOptions());
var view = Mock.Of<IView>();

View File

@ -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<IViewComponentDescriptorProvider>(new FixedSetViewComponentDescriptorProvider(descriptors));
services.AddSingleton<IModelMetadataProvider, EmptyModelMetadataProvider>();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
services.AddSingleton<ITempDataDictionary>(new TempDataDictionary(httpContext, tempDataProvider));
services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<ITempDataDictionaryFactory, TempDataDictionaryFactory>();
services.AddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
services.AddSingleton<HtmlEncoder, HtmlTestEncoder>();
return services;

View File

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

View File

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

View File

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

View File

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

View File

@ -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<ITempDataDictionaryFactory>(MockBehavior.Strict);
tempDataFactory
.Setup(f => f.GetTempData(It.IsAny<HttpContext>()))
.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<ITempDataDictionaryFactory>(MockBehavior.Strict);
tempDataFactory
.Setup(f => f.GetTempData(It.IsAny<HttpContext>()))
.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<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(
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.
}
}
}
}

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()
{
// Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new SessionStateTempDataProvider());
var tempData = new TempDataDictionary(new DefaultHttpContext(), new SessionStateTempDataProvider());
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
@ -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() };
}
}
}

View File

@ -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<IModelMetadataProvider>(new EmptyModelMetadataProvider());
var tempDataProvider = new SessionStateTempDataProvider();
@ -357,6 +357,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
new TestOptionsManager<MvcViewOptions>(),
new TestHttpResponseStreamWriterFactory(),
new Mock<ICompositeViewEngine>(MockBehavior.Strict).Object,
new TempDataDictionaryFactory(new SessionStateTempDataProvider()),
diagnosticSource);
}
}

View File

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

View File

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

View File

@ -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<QueryValueService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
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.
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<RequestIdService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
public void Configure(IApplicationBuilder app)