diff --git a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs index e70133c1fd..0a8504b522 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs @@ -18,7 +18,6 @@ namespace Microsoft.AspNet.Mvc.Core private readonly ControllerActionDescriptor _descriptor; private readonly IControllerFactory _controllerFactory; private readonly IControllerActionArgumentBinder _argumentBinder; - private readonly ITempDataDictionary _tempData; public ControllerActionInvoker( [NotNull] ActionContext actionContext, @@ -32,7 +31,6 @@ namespace Microsoft.AspNet.Mvc.Core [NotNull] IReadOnlyList modelValidatorProviders, [NotNull] IReadOnlyList valueProviderFactories, [NotNull] IScopedInstance actionBindingContextAccessor, - [NotNull] ITempDataDictionary tempData, [NotNull] ILoggerFactory loggerFactory, int maxModelValidationErrors) : base( @@ -50,7 +48,6 @@ namespace Microsoft.AspNet.Mvc.Core _descriptor = descriptor; _controllerFactory = controllerFactory; _argumentBinder = controllerActionArgumentBinder; - _tempData = tempData; if (descriptor.MethodInfo == null) { @@ -70,7 +67,6 @@ namespace Microsoft.AspNet.Mvc.Core protected override void ReleaseInstance(object instance) { - _tempData.Save(); _controllerFactory.ReleaseController(instance); } diff --git a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs index 89140fee73..4699b06a08 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs @@ -22,7 +22,6 @@ namespace Microsoft.AspNet.Mvc.Core private readonly IReadOnlyList _modelValidatorProviders; private readonly IReadOnlyList _valueProviderFactories; private readonly IScopedInstance _actionBindingContextAccessor; - private readonly ITempDataDictionary _tempData; private readonly int _maxModelValidationErrors; private readonly ILoggerFactory _loggerFactory; @@ -32,7 +31,6 @@ namespace Microsoft.AspNet.Mvc.Core IControllerActionArgumentBinder argumentBinder, IOptions optionsAccessor, IScopedInstance actionBindingContextAccessor, - ITempDataDictionary tempData, ILoggerFactory loggerFactory) { _controllerFactory = controllerFactory; @@ -44,7 +42,6 @@ namespace Microsoft.AspNet.Mvc.Core _modelValidatorProviders = optionsAccessor.Options.ModelValidatorProviders.ToArray(); _valueProviderFactories = optionsAccessor.Options.ValueProviderFactories.ToArray(); _actionBindingContextAccessor = actionBindingContextAccessor; - _tempData = tempData; _maxModelValidationErrors = optionsAccessor.Options.MaxModelValidationErrors; _loggerFactory = loggerFactory; } @@ -73,7 +70,6 @@ namespace Microsoft.AspNet.Mvc.Core _modelValidatorProviders, _valueProviderFactories, _actionBindingContextAccessor, - _tempData, _loggerFactory, _maxModelValidationErrors); } diff --git a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs index 9999394bb6..651d311ad4 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs @@ -130,15 +130,6 @@ namespace Microsoft.Framework.DependencyInjection return new DefaultObjectValidator(options.ValidationExcludeFilters, modelMetadataProvider); })); - // - // Temp Data - // - // Holds per-request data so it should be scoped - services.TryAddScoped(); - - // This does caching so it should stay singleton - services.TryAddSingleton(); - // // Random Infrastructure // diff --git a/src/Microsoft.AspNet.Mvc.Core/IKeepTempDataResult.cs b/src/Microsoft.AspNet.Mvc.Core/IKeepTempDataResult.cs new file mode 100644 index 0000000000..3b7f140e9f --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/IKeepTempDataResult.cs @@ -0,0 +1,12 @@ +// 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. + +namespace Microsoft.AspNet.Mvc +{ + /// + /// A marker interface for types which need to have temp data saved. + /// + public interface IKeepTempDataResult : IActionResult + { + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs index ef35c6b217..2431de95bf 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs @@ -874,54 +874,6 @@ namespace Microsoft.AspNet.Mvc.Core return string.Format(CultureInfo.CurrentCulture, GetString("ModelType_WrongType"), p0, p1); } - /// - /// The '{0}' cannot serialize an object of type '{1}' to session state. - /// - internal static string TempData_CannotSerializeToSession - { - get { return GetString("TempData_CannotSerializeToSession"); } - } - - /// - /// The '{0}' cannot serialize an object of type '{1}' to session state. - /// - internal static string FormatTempData_CannotSerializeToSession(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeToSession"), p0, p1); - } - - /// - /// Cannot deserialize {0} of type '{1}'. - /// - internal static string TempData_CannotDeserializeToken - { - get { return GetString("TempData_CannotDeserializeToken"); } - } - - /// - /// Cannot deserialize {0} of type '{1}'. - /// - internal static string FormatTempData_CannotDeserializeToken(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotDeserializeToken"), p0, p1); - } - - /// - /// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state. - /// - internal static string TempData_CannotSerializeDictionary - { - get { return GetString("TempData_CannotSerializeDictionary"); } - } - - /// - /// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state. - /// - internal static string FormatTempData_CannotSerializeDictionary(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeDictionary"), p0, p1); - } - /// /// The type '{0}' cannot be activated by '{1}' because it is either a value type, an interface, an abstract class or an open generic type. /// diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs index a5c0e667c3..53ece18a8b 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs @@ -8,7 +8,7 @@ using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc { - public class RedirectResult : ActionResult + public class RedirectResult : ActionResult, IKeepTempDataResult { private string _url; @@ -60,8 +60,6 @@ namespace Microsoft.AspNet.Mvc destinationUrl = urlHelper.Content(Url); } - var tempData = context.HttpContext.RequestServices.GetRequiredService(); - tempData.Keep(); context.HttpContext.Response.Redirect(destinationUrl, Permanent); } diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs index 8f8e84a2ec..90187f94da 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs @@ -9,7 +9,7 @@ using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc { - public class RedirectToActionResult : ActionResult + public class RedirectToActionResult : ActionResult, IKeepTempDataResult { public RedirectToActionResult( string actionName, @@ -51,8 +51,6 @@ namespace Microsoft.AspNet.Mvc throw new InvalidOperationException(Resources.NoRoutesMatched); } - var tempData = context.HttpContext.RequestServices.GetRequiredService(); - tempData.Keep(); context.HttpContext.Response.Redirect(destinationUrl, Permanent); } diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs index d7c5639964..d2658fc5b6 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs @@ -9,7 +9,7 @@ using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc { - public class RedirectToRouteResult : ActionResult + public class RedirectToRouteResult : ActionResult, IKeepTempDataResult { public RedirectToRouteResult(object routeValues) : this(routeName: null, routeValues: routeValues) @@ -51,8 +51,6 @@ namespace Microsoft.AspNet.Mvc throw new InvalidOperationException(Resources.NoRoutesMatched); } - var tempData = context.HttpContext.RequestServices.GetRequiredService(); - tempData.Keep(); context.HttpContext.Response.Redirect(destinationUrl, Permanent); } diff --git a/src/Microsoft.AspNet.Mvc.Core/Resources.resx b/src/Microsoft.AspNet.Mvc.Core/Resources.resx index 7ba416e14c..679efad938 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.Core/Resources.resx @@ -288,15 +288,6 @@ The model's runtime type '{0}' is not assignable to the type '{1}'. - - The '{0}' cannot serialize an object of type '{1}' to session state. - - - Cannot deserialize {0} of type '{1}'. - - - The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state. - The type '{0}' cannot be activated by '{1}' because it is either a value type, an interface, an abstract class or an open generic type. diff --git a/src/Microsoft.AspNet.Mvc.Core/project.json b/src/Microsoft.AspNet.Mvc.Core/project.json index 3afff3b00f..0751834532 100644 --- a/src/Microsoft.AspNet.Mvc.Core/project.json +++ b/src/Microsoft.AspNet.Mvc.Core/project.json @@ -14,15 +14,15 @@ "Microsoft.AspNet.Hosting.Abstractions": "1.0.0-*", "Microsoft.AspNet.Http": "1.0.0-*", "Microsoft.AspNet.Mvc.Abstractions": "6.0.0-*", + "Microsoft.Dnx.Runtime.Abstractions": "1.0.0-*", "Microsoft.Framework.ClosedGenericMatcher.Sources": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.Logging.Abstractions": "1.0.0-*", "Microsoft.Framework.Notification": "1.0.0-*", "Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.PropertyActivator.Sources": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" }, - "Microsoft.Framework.SecurityHelper.Sources": { "version": "1.0.0-*", "type": "build" }, - "Microsoft.Dnx.Compilation.Abstractions": "1.0.0-*", - "Newtonsoft.Json": "6.0.6" + "Microsoft.Framework.SecurityHelper.Sources": { "version": "1.0.0-*", "type": "build" } + }, "frameworks": { "dnx451": { }, diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs index b49c61e781..feb9be9aa3 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs @@ -51,6 +51,8 @@ namespace Microsoft.Framework.DependencyInjection services.TryAddEnumerable( ServiceDescriptor.Transient, MvcViewOptionsSetup>()); + services.TryAddEnumerable( + ServiceDescriptor.Transient, TempDataMvcOptionsSetup>()); // // View Engine and related infrastructure @@ -95,6 +97,16 @@ namespace Microsoft.Framework.DependencyInjection services.TryAddTransient(); services.TryAddSingleton(); services.TryAddTransient(); + + // + // 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(); } } } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs index d5487e2034..bbfaf4292c 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Properties/Resources.Designer.cs @@ -794,6 +794,54 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponentResult_NameOrTypeMustBeSet"), p0, p1); } + /// + /// Cannot deserialize {0} of type '{1}'. + /// + internal static string TempData_CannotDeserializeToken + { + get { return GetString("TempData_CannotDeserializeToken"); } + } + + /// + /// Cannot deserialize {0} of type '{1}'. + /// + internal static string FormatTempData_CannotDeserializeToken(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotDeserializeToken"), p0, p1); + } + + /// + /// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state. + /// + internal static string TempData_CannotSerializeDictionary + { + get { return GetString("TempData_CannotSerializeDictionary"); } + } + + /// + /// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state. + /// + internal static string FormatTempData_CannotSerializeDictionary(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeDictionary"), p0, p1); + } + + /// + /// The '{0}' cannot serialize an object of type '{1}' to session state. + /// + internal static string TempData_CannotSerializeToSession + { + get { return GetString("TempData_CannotSerializeToSession"); } + } + + /// + /// The '{0}' cannot serialize an object of type '{1}' to session state. + /// + internal static string FormatTempData_CannotSerializeToSession(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeToSession"), p0, p1); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx b/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx index 52868bec65..3abf07efde 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Resources.resx @@ -265,4 +265,13 @@ Either the '{0}' or '{1}' property must be set in order to invoke a view component. + + Cannot deserialize {0} of type '{1}'. + + + The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state. + + + The '{0}' cannot serialize an object of type '{1}' to session state. + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/ITempDataDictionary.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/ITempDataDictionary.cs similarity index 100% rename from src/Microsoft.AspNet.Mvc.Core/ITempDataDictionary.cs rename to src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/ITempDataDictionary.cs diff --git a/src/Microsoft.AspNet.Mvc.Core/ITempDataProvider.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/ITempDataProvider.cs similarity index 100% rename from src/Microsoft.AspNet.Mvc.Core/ITempDataProvider.cs rename to src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/ITempDataProvider.cs diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SaveTempDataAttribute.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SaveTempDataAttribute.cs new file mode 100644 index 0000000000..a3a9b13a6c --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SaveTempDataAttribute.cs @@ -0,0 +1,21 @@ +// 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.Framework.DependencyInjection; + +namespace Microsoft.AspNet.Mvc +{ + /// + /// Adds a filter which will save the for a request. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class SaveTempDataAttribute : Attribute, IFilterFactory + { + /// + public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) + { + return serviceProvider.GetRequiredService(); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SaveTempDataFilter.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SaveTempDataFilter.cs new file mode 100644 index 0000000000..f1d7216198 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SaveTempDataFilter.cs @@ -0,0 +1,47 @@ +// 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. + +namespace Microsoft.AspNet.Mvc +{ + /// + /// A filter which saves temp data. + /// + public class SaveTempDataFilter : IResourceFilter, IResultFilter + { + private readonly ITempDataDictionary _tempData; + + /// + /// Creates a new instance of . + /// + /// The for the current request. + public SaveTempDataFilter(ITempDataDictionary tempData) + { + _tempData = tempData; + } + + /// + public void OnResourceExecuting(ResourceExecutingContext context) + { + } + + /// + public void OnResourceExecuted(ResourceExecutedContext context) + { + _tempData.Save(); + } + + /// + public void OnResultExecuting(ResultExecutingContext context) + { + } + + /// + public void OnResultExecuted(ResultExecutedContext context) + { + if (context.Result is IKeepTempDataResult) + { + _tempData.Keep(); + } + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/SessionStateTempDataProvider.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SessionStateTempDataProvider.cs similarity index 99% rename from src/Microsoft.AspNet.Mvc.Core/SessionStateTempDataProvider.cs rename to src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SessionStateTempDataProvider.cs index 05e96716a5..eab56d2b4f 100644 --- a/src/Microsoft.AspNet.Mvc.Core/SessionStateTempDataProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/SessionStateTempDataProvider.cs @@ -10,7 +10,7 @@ using System.Linq; using System.Reflection; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Features; -using Microsoft.AspNet.Mvc.Core; +using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.Framework.Internal; using Newtonsoft.Json; using Newtonsoft.Json.Bson; diff --git a/src/Microsoft.AspNet.Mvc.Core/TempDataDictionary.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/TempDataDictionary.cs similarity index 100% rename from src/Microsoft.AspNet.Mvc.Core/TempDataDictionary.cs rename to src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/TempDataDictionary.cs diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/TempDataMvcOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/TempDataMvcOptionsSetup.cs new file mode 100644 index 0000000000..ddcbc90dc1 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/TempData/TempDataMvcOptionsSetup.cs @@ -0,0 +1,24 @@ +// 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.Framework.OptionsModel; + +namespace Microsoft.AspNet.Mvc +{ + /// + /// Sets up default options for . + /// + public class TempDataMvcOptionsSetup : ConfigureOptions + { + public TempDataMvcOptionsSetup() + : base(ConfigureMvc) + { + Order = DefaultOrder.DefaultFrameworkSortOrder; + } + + public static void ConfigureMvc(MvcOptions options) + { + options.Filters.Add(new SaveTempDataAttribute()); + } + } +} diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs index 9109d70116..263901f481 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs @@ -54,36 +54,6 @@ namespace Microsoft.AspNet.Mvc filter.Verify(f => f.OnException(It.IsAny()), Times.Never()); } - [Fact] - public async Task InvokeAction_SavesTempData_WhenActionDoesNotThrow() - { - // Arrange - var tempData = new Mock(); - tempData.Setup(t => t.Save()).Verifiable(); - - var invoker = CreateInvoker(Mock.Of(), actionThrows: false, tempData: tempData.Object); - - // Act - await invoker.InvokeAsync(); - - // Assert - tempData.Verify(t => t.Save(), Times.Once()); - } - - [Fact] - public async Task InvokeAction_SavesTempData_WhenActionThrows() - { - // Arrange - var tempData = new Mock(); - tempData.Setup(t => t.Save()).Verifiable(); - - var invoker = CreateInvoker(Mock.Of(), actionThrows: true, tempData: tempData.Object); - - // Act & Assert - await Assert.ThrowsAsync(_actionException.GetType(), async () => await invoker.InvokeAsync()); - tempData.Verify(t => t.Save(), Times.Once()); - } - [Fact] public async Task InvokeAction_DoesNotAsyncInvokeExceptionFilter_WhenActionDoesNotThrow() { @@ -1967,7 +1937,6 @@ namespace Microsoft.AspNet.Mvc var invoker = CreateInvoker( filter, actionThrows: false, - tempData: null, maxAllowedErrorsInModelState: expected); // Act & Assert @@ -1978,16 +1947,14 @@ namespace Microsoft.AspNet.Mvc private TestControllerActionInvoker CreateInvoker( IFilterMetadata filter, bool actionThrows = false, - ITempDataDictionary tempData = null, int maxAllowedErrorsInModelState = 200) { - return CreateInvoker(new[] { filter }, actionThrows, tempData, maxAllowedErrorsInModelState); + return CreateInvoker(new[] { filter }, actionThrows, maxAllowedErrorsInModelState); } private TestControllerActionInvoker CreateInvoker( IFilterMetadata[] filters, bool actionThrows = false, - ITempDataDictionary tempData = null, int maxAllowedErrorsInModelState = 200) { var actionDescriptor = new ControllerActionDescriptor() @@ -2004,16 +1971,13 @@ namespace Microsoft.AspNet.Mvc { actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod("ActionMethod"); } - - tempData = tempData ?? new Mock().Object; + var httpContext = new Mock(MockBehavior.Loose); var httpRequest = new DefaultHttpContext().Request; var httpResponse = new DefaultHttpContext().Response; httpContext.SetupGet(c => c.Request).Returns(httpRequest); httpContext.SetupGet(c => c.Response).Returns(httpResponse); - httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary))) - .Returns(tempData); httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger))) .Returns(new Mock>().Object); @@ -2077,7 +2041,6 @@ namespace Microsoft.AspNet.Mvc new IModelValidatorProvider[0], new IValueProviderFactory[0], new MockScopedInstance(), - tempData, new NullLoggerFactory(), maxAllowedErrorsInModelState); @@ -2140,7 +2103,6 @@ namespace Microsoft.AspNet.Mvc new IModelValidatorProvider[0], new IValueProviderFactory[0], new MockScopedInstance(), - Mock.Of(), new NullLoggerFactory(), 200); @@ -2241,7 +2203,6 @@ namespace Microsoft.AspNet.Mvc IReadOnlyList modelValidatorProviders, IReadOnlyList valueProviderFactories, IScopedInstance actionBindingContext, - ITempDataDictionary tempData, ILoggerFactory loggerFactory, int maxAllowedErrorsInModelState) : base( @@ -2256,7 +2217,6 @@ namespace Microsoft.AspNet.Mvc modelValidatorProviders, valueProviderFactories, actionBindingContext, - tempData, loggerFactory, maxAllowedErrorsInModelState) { diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs index 4a6244fdd7..4392eab04b 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs @@ -91,30 +91,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test httpResponse.Verify(); } - [Fact] - public void Execute_Calls_TempDataKeep() - { - // Arrange - var tempData = new Mock(); - tempData.Setup(t => t.Keep()).Verifiable(); - - var httpContext = new Mock(); - httpContext.Setup(o => o.Response).Returns(new Mock().Object); - httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary))).Returns(tempData.Object); - var actionContext = GetActionContext(httpContext.Object); - - var result = new RedirectResult("url") - { - UrlHelper = Mock.Of() - }; - - // Act - result.ExecuteResult(actionContext); - - // Assert - tempData.Verify(t => t.Keep(), Times.Once()); - } - private static ActionContext GetActionContext(HttpContext httpContext) { var routeData = new RouteData(); @@ -129,7 +105,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test { var serviceCollection = new ServiceCollection(); serviceCollection.AddInstance(urlHelper); - serviceCollection.AddInstance(Mock.Of()); return serviceCollection.BuildServiceProvider(); } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToActionResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToActionResultTest.cs index 606e273f91..abdbe225e0 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToActionResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToActionResultTest.cs @@ -68,32 +68,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults "No route matches the supplied values."); } - [Fact] - public void RedirectToAction_Execute_Calls_TempDataKeep() - { - // Arrange - var tempData = new Mock(); - tempData.Setup(t => t.Keep()).Verifiable(); - - var httpContext = new Mock(); - httpContext.Setup(o => o.Response).Returns(new Mock().Object); - httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary))).Returns(tempData.Object); - var actionContext = new ActionContext(httpContext.Object, - new RouteData(), - new ActionDescriptor()); - - var result = new RedirectToActionResult("SampleAction", null, null) - { - UrlHelper = GetMockUrlHelper("SampleAction") - }; - - // Act - result.ExecuteResult(actionContext); - - // Assert - tempData.Verify(t => t.Keep(), Times.Once()); - } - private static IUrlHelper GetMockUrlHelper(string returnValue) { var urlHelper = new Mock(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs index 01583b6306..b8abbb8c71 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs @@ -74,32 +74,6 @@ namespace Microsoft.AspNet.Mvc.Core "No route matches the supplied values."); } - [Fact] - public void RedirectToRoute_Execute_Calls_TempDataKeep() - { - // Arrange - var tempData = new Mock(); - tempData.Setup(t => t.Keep()).Verifiable(); - - var httpContext = new Mock(); - httpContext.Setup(o => o.Response).Returns(new Mock().Object); - httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary))).Returns(tempData.Object); - var actionContext = new ActionContext(httpContext.Object, - new RouteData(), - new ActionDescriptor()); - - var result = new RedirectToRouteResult("SampleRoute", null) - { - UrlHelper = GetMockUrlHelper("SampleRoute") - }; - - // Act - result.ExecuteResult(actionContext); - - // Assert - tempData.Verify(t => t.Keep(), Times.Once()); - } - [Fact] public async Task ExecuteResultAsync_UsesRouteName_ToGenerateLocationHeader() { diff --git a/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs index f2dfc5ae9b..e091a1e6fe 100644 --- a/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs @@ -205,6 +205,7 @@ namespace Microsoft.AspNet.Mvc typeof(MvcCoreMvcOptionsSetup), typeof(MvcDataAnnotationsMvcOptionsSetup), typeof(MvcJsonMvcOptionsSetup), + typeof(TempDataMvcOptionsSetup), } }, { diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/TempData/SaveTempDataFilterTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/TempData/SaveTempDataFilterTest.cs new file mode 100644 index 0000000000..7a7c536866 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/TempData/SaveTempDataFilterTest.cs @@ -0,0 +1,74 @@ +// 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 Moq; +using Xunit; + +namespace Microsoft.AspNet.Mvc +{ + public class SaveTempDataFilterTest + { + [Fact] + public void SaveTempDataFilter_OnResourceExecuted_SavesTempData() + { + // Arrange + var tempData = new Mock(MockBehavior.Strict); + tempData + .Setup(m => m.Save()) + .Verifiable(); + + var filter = new SaveTempDataFilter(tempData.Object); + + var context = new ResourceExecutedContext(new ActionContext(), new IFilterMetadata[] { }); + + // Act + filter.OnResourceExecuted(context); + + // Assert + tempData.Verify(); + } + + [Fact] + public void SaveTempDataFilter_OnResultExecuted_KeepsTempData_ForIKeepTempDataResult() + { + // Arrange + var tempData = new Mock(MockBehavior.Strict); + tempData + .Setup(m => m.Keep()) + .Verifiable(); + + var filter = new SaveTempDataFilter(tempData.Object); + + var context = new ResultExecutedContext( + new ActionContext(), + new IFilterMetadata[] { }, + new Mock().Object, + new object()); + + // Act + filter.OnResultExecuted(context); + + // Assert + tempData.Verify(); + } + + [Fact] + public void SaveTempDataFilter_OnResultExecuted_DoesNotKeepTempData_ForNonIKeepTempDataResult() + { + // Arrange + var tempData = new Mock(MockBehavior.Strict); + var filter = new SaveTempDataFilter(tempData.Object); + + var context = new ResultExecutedContext( + new ActionContext(), + new IFilterMetadata[] { }, + new Mock().Object, + new object()); + + // Act + filter.OnResultExecuted(context); + + // Assert - The mock will throw if we do the wrong thing. + } + } +} diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/SessionStateTempDataProviderTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/TempData/SessionStateTempDataProviderTest.cs similarity index 100% rename from test/Microsoft.AspNet.Mvc.Core.Test/SessionStateTempDataProviderTest.cs rename to test/Microsoft.AspNet.Mvc.ViewFeatures.Test/TempData/SessionStateTempDataProviderTest.cs diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/TempDataDictionaryTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/TempData/TempDataDictionaryTest.cs similarity index 100% rename from test/Microsoft.AspNet.Mvc.Core.Test/TempDataDictionaryTest.cs rename to test/Microsoft.AspNet.Mvc.ViewFeatures.Test/TempData/TempDataDictionaryTest.cs