Make saving TempData operate via a filter
This change moves the responsibility for saving TempData into a filter, which is registered with other View features. This moves TempData into the ViewFeatures package. ActionResults which require TempData to be kept use a new marker interface which is handled by the filter.
This commit is contained in:
parent
b5237b29b5
commit
ff6cbfd7cf
|
|
@ -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<IModelValidatorProvider> modelValidatorProviders,
|
||||
[NotNull] IReadOnlyList<IValueProviderFactory> valueProviderFactories,
|
||||
[NotNull] IScopedInstance<ActionBindingContext> 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
|
||||
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
|
||||
private readonly IScopedInstance<ActionBindingContext> _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<MvcOptions> optionsAccessor,
|
||||
IScopedInstance<ActionBindingContext> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ITempDataDictionary, TempDataDictionary>();
|
||||
|
||||
// This does caching so it should stay singleton
|
||||
services.TryAddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
|
||||
|
||||
//
|
||||
// Random Infrastructure
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A marker interface for <see cref="IActionResult"/> types which need to have temp data saved.
|
||||
/// </summary>
|
||||
public interface IKeepTempDataResult : IActionResult
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -874,54 +874,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("ModelType_WrongType"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize an object of type '{1}' to session state.
|
||||
/// </summary>
|
||||
internal static string TempData_CannotSerializeToSession
|
||||
{
|
||||
get { return GetString("TempData_CannotSerializeToSession"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize an object of type '{1}' to session state.
|
||||
/// </summary>
|
||||
internal static string FormatTempData_CannotSerializeToSession(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeToSession"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot deserialize {0} of type '{1}'.
|
||||
/// </summary>
|
||||
internal static string TempData_CannotDeserializeToken
|
||||
{
|
||||
get { return GetString("TempData_CannotDeserializeToken"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot deserialize {0} of type '{1}'.
|
||||
/// </summary>
|
||||
internal static string FormatTempData_CannotDeserializeToken(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotDeserializeToken"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state.
|
||||
/// </summary>
|
||||
internal static string TempData_CannotSerializeDictionary
|
||||
{
|
||||
get { return GetString("TempData_CannotSerializeDictionary"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state.
|
||||
/// </summary>
|
||||
internal static string FormatTempData_CannotSerializeDictionary(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeDictionary"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -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<ITempDataDictionary>();
|
||||
tempData.Keep();
|
||||
context.HttpContext.Response.Redirect(destinationUrl, Permanent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ITempDataDictionary>();
|
||||
tempData.Keep();
|
||||
context.HttpContext.Response.Redirect(destinationUrl, Permanent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ITempDataDictionary>();
|
||||
tempData.Keep();
|
||||
context.HttpContext.Response.Redirect(destinationUrl, Permanent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -288,15 +288,6 @@
|
|||
<data name="ModelType_WrongType" xml:space="preserve">
|
||||
<value>The model's runtime type '{0}' is not assignable to the type '{1}'.</value>
|
||||
</data>
|
||||
<data name="TempData_CannotSerializeToSession" xml:space="preserve">
|
||||
<value>The '{0}' cannot serialize an object of type '{1}' to session state.</value>
|
||||
</data>
|
||||
<data name="TempData_CannotDeserializeToken" xml:space="preserve">
|
||||
<value>Cannot deserialize {0} of type '{1}'.</value>
|
||||
</data>
|
||||
<data name="TempData_CannotSerializeDictionary" xml:space="preserve">
|
||||
<value>The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state.</value>
|
||||
</data>
|
||||
<data name="ValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -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": { },
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcViewOptionsSetup>());
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, TempDataMvcOptionsSetup>());
|
||||
|
||||
//
|
||||
// View Engine and related infrastructure
|
||||
|
|
@ -95,6 +97,16 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
services.TryAddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
|
||||
services.TryAddSingleton<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
||||
services.TryAddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
|
||||
|
||||
//
|
||||
// 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -794,6 +794,54 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponentResult_NameOrTypeMustBeSet"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot deserialize {0} of type '{1}'.
|
||||
/// </summary>
|
||||
internal static string TempData_CannotDeserializeToken
|
||||
{
|
||||
get { return GetString("TempData_CannotDeserializeToken"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot deserialize {0} of type '{1}'.
|
||||
/// </summary>
|
||||
internal static string FormatTempData_CannotDeserializeToken(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotDeserializeToken"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state.
|
||||
/// </summary>
|
||||
internal static string TempData_CannotSerializeDictionary
|
||||
{
|
||||
get { return GetString("TempData_CannotSerializeDictionary"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state.
|
||||
/// </summary>
|
||||
internal static string FormatTempData_CannotSerializeDictionary(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeDictionary"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize an object of type '{1}' to session state.
|
||||
/// </summary>
|
||||
internal static string TempData_CannotSerializeToSession
|
||||
{
|
||||
get { return GetString("TempData_CannotSerializeToSession"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The '{0}' cannot serialize an object of type '{1}' to session state.
|
||||
/// </summary>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -265,4 +265,13 @@
|
|||
<data name="ViewComponentResult_NameOrTypeMustBeSet" xml:space="preserve">
|
||||
<value>Either the '{0}' or '{1}' property must be set in order to invoke a view component.</value>
|
||||
</data>
|
||||
<data name="TempData_CannotDeserializeToken" xml:space="preserve">
|
||||
<value>Cannot deserialize {0} of type '{1}'.</value>
|
||||
</data>
|
||||
<data name="TempData_CannotSerializeDictionary" xml:space="preserve">
|
||||
<value>The '{0}' cannot serialize a dictionary with a key of type '{1}' to session state.</value>
|
||||
</data>
|
||||
<data name="TempData_CannotSerializeToSession" xml:space="preserve">
|
||||
<value>The '{0}' cannot serialize an object of type '{1}' to session state.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a filter which will save the <see cref="ITempDataDictionary"/> for a request.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
public class SaveTempDataAttribute : Attribute, IFilterFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
return serviceProvider.GetRequiredService<SaveTempDataFilter>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A filter which saves temp data.
|
||||
/// </summary>
|
||||
public class SaveTempDataFilter : IResourceFilter, IResultFilter
|
||||
{
|
||||
private readonly ITempDataDictionary _tempData;
|
||||
|
||||
/// <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)
|
||||
{
|
||||
_tempData = tempData;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||
{
|
||||
_tempData.Save();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnResultExecuted(ResultExecutedContext context)
|
||||
{
|
||||
if (context.Result is IKeepTempDataResult)
|
||||
{
|
||||
_tempData.Keep();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets up default options for <see cref="MvcOptions"/>.
|
||||
/// </summary>
|
||||
public class TempDataMvcOptionsSetup : ConfigureOptions<MvcOptions>
|
||||
{
|
||||
public TempDataMvcOptionsSetup()
|
||||
: base(ConfigureMvc)
|
||||
{
|
||||
Order = DefaultOrder.DefaultFrameworkSortOrder;
|
||||
}
|
||||
|
||||
public static void ConfigureMvc(MvcOptions options)
|
||||
{
|
||||
options.Filters.Add(new SaveTempDataAttribute());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,36 +54,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
filter.Verify(f => f.OnException(It.IsAny<ExceptionContext>()), Times.Never());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAction_SavesTempData_WhenActionDoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new Mock<ITempDataDictionary>();
|
||||
tempData.Setup(t => t.Save()).Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(Mock.Of<IFilterMetadata>(), 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<ITempDataDictionary>();
|
||||
tempData.Setup(t => t.Save()).Verifiable();
|
||||
|
||||
var invoker = CreateInvoker(Mock.Of<IFilterMetadata>(), 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<ITempDataDictionary>().Object;
|
||||
|
||||
var httpContext = new Mock<HttpContext>(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<ObjectResult>)))
|
||||
.Returns(new Mock<ILogger<ObjectResult>>().Object);
|
||||
|
||||
|
|
@ -2077,7 +2041,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
new IModelValidatorProvider[0],
|
||||
new IValueProviderFactory[0],
|
||||
new MockScopedInstance<ActionBindingContext>(),
|
||||
tempData,
|
||||
new NullLoggerFactory(),
|
||||
maxAllowedErrorsInModelState);
|
||||
|
||||
|
|
@ -2140,7 +2103,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
new IModelValidatorProvider[0],
|
||||
new IValueProviderFactory[0],
|
||||
new MockScopedInstance<ActionBindingContext>(),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
new NullLoggerFactory(),
|
||||
200);
|
||||
|
||||
|
|
@ -2241,7 +2203,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
|
||||
IReadOnlyList<IValueProviderFactory> valueProviderFactories,
|
||||
IScopedInstance<ActionBindingContext> actionBindingContext,
|
||||
ITempDataDictionary tempData,
|
||||
ILoggerFactory loggerFactory,
|
||||
int maxAllowedErrorsInModelState)
|
||||
: base(
|
||||
|
|
@ -2256,7 +2217,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
modelValidatorProviders,
|
||||
valueProviderFactories,
|
||||
actionBindingContext,
|
||||
tempData,
|
||||
loggerFactory,
|
||||
maxAllowedErrorsInModelState)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -91,30 +91,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
httpResponse.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_Calls_TempDataKeep()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new Mock<ITempDataDictionary>();
|
||||
tempData.Setup(t => t.Keep()).Verifiable();
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.Setup(o => o.Response).Returns(new Mock<HttpResponse>().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<IUrlHelper>()
|
||||
};
|
||||
|
||||
// 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<IUrlHelper>(urlHelper);
|
||||
serviceCollection.AddInstance<ITempDataDictionary>(Mock.Of<ITempDataDictionary>());
|
||||
return serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ITempDataDictionary>();
|
||||
tempData.Setup(t => t.Keep()).Verifiable();
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.Setup(o => o.Response).Returns(new Mock<HttpResponse>().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<IUrlHelper>();
|
||||
|
|
|
|||
|
|
@ -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<ITempDataDictionary>();
|
||||
tempData.Setup(t => t.Keep()).Verifiable();
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.Setup(o => o.Response).Returns(new Mock<HttpResponse>().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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
typeof(MvcCoreMvcOptionsSetup),
|
||||
typeof(MvcDataAnnotationsMvcOptionsSetup),
|
||||
typeof(MvcJsonMvcOptionsSetup),
|
||||
typeof(TempDataMvcOptionsSetup),
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<ITempDataDictionary>(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<ITempDataDictionary>(MockBehavior.Strict);
|
||||
tempData
|
||||
.Setup(m => m.Keep())
|
||||
.Verifiable();
|
||||
|
||||
var filter = new SaveTempDataFilter(tempData.Object);
|
||||
|
||||
var context = new ResultExecutedContext(
|
||||
new ActionContext(),
|
||||
new IFilterMetadata[] { },
|
||||
new Mock<IKeepTempDataResult>().Object,
|
||||
new object());
|
||||
|
||||
// Act
|
||||
filter.OnResultExecuted(context);
|
||||
|
||||
// Assert
|
||||
tempData.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SaveTempDataFilter_OnResultExecuted_DoesNotKeepTempData_ForNonIKeepTempDataResult()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new Mock<ITempDataDictionary>(MockBehavior.Strict);
|
||||
var filter = new SaveTempDataFilter(tempData.Object);
|
||||
|
||||
var context = new ResultExecutedContext(
|
||||
new ActionContext(),
|
||||
new IFilterMetadata[] { },
|
||||
new Mock<IActionResult>().Object,
|
||||
new object());
|
||||
|
||||
// Act
|
||||
filter.OnResultExecuted(context);
|
||||
|
||||
// Assert - The mock will throw if we do the wrong thing.
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue