Introducing TempData
- Issue #455 - Updated MVC sample - Added relevant tests
This commit is contained in:
parent
4e9e33fc07
commit
db728cd386
17
Mvc.sln
17
Mvc.sln
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.22602.0
|
||||
VisualStudioVersion = 14.0.22609.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||
EndProject
|
||||
|
|
@ -148,6 +148,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BestEffortLinkGenerationWeb
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LowercaseUrlsWebSite", "test\WebSites\LowercaseUrlsWebSite\LowercaseUrlsWebSite.kproj", "{BCDB13A6-7D6E-485E-8424-A156432B71AC}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TempDataWebSite", "test\WebSites\TempDataWebSite\TempDataWebSite.kproj", "{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -866,6 +868,18 @@ Global
|
|||
{BCDB13A6-7D6E-485E-8424-A156432B71AC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{BCDB13A6-7D6E-485E-8424-A156432B71AC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{BCDB13A6-7D6E-485E-8424-A156432B71AC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -938,5 +952,6 @@ Global
|
|||
{A19022EF-9BA3-4349-94E4-F48E13E1C8AE} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{B11C99C9-E577-4CA2-AC53-4F20EA71AD34} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{BCDB13A6-7D6E-485E-8424-A156432B71AC} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -113,6 +113,21 @@ namespace MvcSample.Web
|
|||
return View();
|
||||
}
|
||||
|
||||
public ActionResult AddTempData()
|
||||
{
|
||||
TempData["controllerData"] = "Temporary data from controller through ViewBag.";
|
||||
TempData["tempData"] = "Temporary data directly from TempData.";
|
||||
return RedirectToAction("UseTempData");
|
||||
}
|
||||
|
||||
public ActionResult UseTempData()
|
||||
{
|
||||
var data = TempData["controllerData"];
|
||||
ViewBag.TempData = data;
|
||||
|
||||
return View("MyView", CreateUser());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action that exercises input formatter
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Microsoft.AspNet.Authorization;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
|
|
@ -41,6 +38,9 @@ namespace MvcSample.Web
|
|||
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddCachingServices();
|
||||
services.AddSessionServices();
|
||||
|
||||
services.AddMvc();
|
||||
services.AddSingleton<PassThroughAttribute>();
|
||||
services.AddSingleton<UserNameService>();
|
||||
|
|
@ -83,6 +83,9 @@ namespace MvcSample.Web
|
|||
{
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddCachingServices();
|
||||
services.AddSessionServices();
|
||||
|
||||
services.AddMvc();
|
||||
services.AddSingleton<PassThroughAttribute>();
|
||||
services.AddSingleton<UserNameService>();
|
||||
|
|
@ -102,6 +105,7 @@ namespace MvcSample.Web
|
|||
});
|
||||
}
|
||||
|
||||
app.UseInMemorySession();
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("areaRoute", "{area:exists}/{controller}/{action}");
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
<h1>ASP.NET</h1>
|
||||
<p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
|
||||
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more »</a></p>
|
||||
<h3 style="color: red">@ViewBag.TempData<br/>@TempData["tempData"]</h3>
|
||||
File Upload Demo: <br/>
|
||||
<form action="Home/PostFile" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="files" id="file1" />
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-*",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.AspNet.Session": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*",
|
||||
"Microsoft.Framework.PropertyHelper.Internal": { "version": "1.0.0-*", "type": "build" },
|
||||
"Microsoft.Framework.NotNullAttribute.Internal": { "type": "build", "version": "1.0.0-*" }
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ITempDataDictionary"/> used for rendering the view for this result.
|
||||
/// </summary>
|
||||
public ITempDataDictionary TempData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IViewEngine"/> used to locate views.
|
||||
/// </summary>
|
||||
|
|
@ -57,7 +62,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
using (view as IDisposable)
|
||||
{
|
||||
await ViewExecutor.ExecuteAsync(view, context, ViewData, contentType: null);
|
||||
await ViewExecutor.ExecuteAsync(view, context, ViewData, TempData, contentType: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
destinationUrl = urlHelper.Content(Url);
|
||||
}
|
||||
|
||||
var tempData = context.HttpContext.RequestServices.GetRequiredService<ITempDataDictionary>();
|
||||
tempData.Keep();
|
||||
context.HttpContext.Response.Redirect(destinationUrl, Permanent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
throw new InvalidOperationException(Resources.NoRoutesMatched);
|
||||
}
|
||||
|
||||
var tempData = context.HttpContext.RequestServices.GetRequiredService<ITempDataDictionary>();
|
||||
tempData.Keep();
|
||||
context.HttpContext.Response.Redirect(destinationUrl, Permanent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
throw new InvalidOperationException(Resources.NoRoutesMatched);
|
||||
}
|
||||
|
||||
var tempData = context.HttpContext.RequestServices.GetRequiredService<ITempDataDictionary>();
|
||||
tempData.Keep();
|
||||
context.HttpContext.Response.Redirect(destinationUrl, Permanent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// <param name="view">The <see cref="IView"/> to render.</param>
|
||||
/// <param name="actionContext">The <see cref="ActionContext"/> for the current executing action.</param>
|
||||
/// <param name="viewData">The <see cref="ViewDataDictionary"/> for the view being rendered.</param>
|
||||
/// <param name="tempData">The <see cref="ITempDataDictionary"/> for the view being rendered.</param>
|
||||
/// <returns>A <see cref="Task"/> that represents the asychronous rendering.</returns>
|
||||
public static async Task ExecuteAsync([NotNull] IView view,
|
||||
[NotNull] ActionContext actionContext,
|
||||
[NotNull] ViewDataDictionary viewData,
|
||||
[NotNull] ITempDataDictionary tempData,
|
||||
string contentType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(contentType))
|
||||
|
|
@ -40,7 +42,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
try
|
||||
{
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, writer);
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, tempData, writer);
|
||||
await view.RenderAsync(viewContext);
|
||||
}
|
||||
catch
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ITempDataDictionary"/> for this result.
|
||||
/// </summary>
|
||||
public ITempDataDictionary TempData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IViewEngine"/> used to locate views.
|
||||
/// </summary>
|
||||
|
|
@ -57,7 +62,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
using (view as IDisposable)
|
||||
{
|
||||
await ViewExecutor.ExecuteAsync(view, context, ViewData, contentType: null);
|
||||
await ViewExecutor.ExecuteAsync(view, context, ViewData, TempData, contentType: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,6 +185,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets <see cref="ITempDataDictionary"/> used by <see cref="ViewResult"/>.
|
||||
/// </summary>
|
||||
[FromServices]
|
||||
public ITempDataDictionary TempData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dynamic view bag.
|
||||
/// </summary>
|
||||
|
|
@ -254,6 +260,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
ViewName = viewName,
|
||||
ViewData = ViewData,
|
||||
TempData = TempData
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -310,6 +317,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
ViewName = viewName,
|
||||
ViewData = ViewData,
|
||||
TempData = TempData
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ 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,
|
||||
|
|
@ -27,7 +28,8 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
[NotNull] IModelBinderProvider modelBinderProvider,
|
||||
[NotNull] IModelValidatorProviderProvider modelValidatorProviderProvider,
|
||||
[NotNull] IValueProviderFactoryProvider valueProviderFactoryProvider,
|
||||
[NotNull] IScopedInstance<ActionBindingContext> actionBindingContextAccessor)
|
||||
[NotNull] IScopedInstance<ActionBindingContext> actionBindingContextAccessor,
|
||||
[NotNull] ITempDataDictionary tempData)
|
||||
: base(
|
||||
actionContext,
|
||||
filterProviders,
|
||||
|
|
@ -40,6 +42,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
_descriptor = descriptor;
|
||||
_controllerFactory = controllerFactory;
|
||||
_argumentBinder = controllerActionArgumentBinder;
|
||||
_tempData = tempData;
|
||||
|
||||
if (descriptor.MethodInfo == null)
|
||||
{
|
||||
|
|
@ -59,6 +62,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
|
||||
protected override void ReleaseInstance(object instance)
|
||||
{
|
||||
_tempData.Save();
|
||||
_controllerFactory.ReleaseController(instance);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
private readonly IModelValidatorProviderProvider _modelValidationProviderProvider;
|
||||
private readonly IValueProviderFactoryProvider _valueProviderFactoryProvider;
|
||||
private readonly IScopedInstance<ActionBindingContext> _actionBindingContextAccessor;
|
||||
private readonly ITempDataDictionary _tempData;
|
||||
|
||||
public ControllerActionInvokerProvider(
|
||||
IControllerFactory controllerFactory,
|
||||
|
|
@ -29,7 +30,8 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
IModelBinderProvider modelBinderProvider,
|
||||
IModelValidatorProviderProvider modelValidationProviderProvider,
|
||||
IValueProviderFactoryProvider valueProviderFactoryProvider,
|
||||
IScopedInstance<ActionBindingContext> actionBindingContextAccessor)
|
||||
IScopedInstance<ActionBindingContext> actionBindingContextAccessor,
|
||||
ITempDataDictionary tempData)
|
||||
{
|
||||
_controllerFactory = controllerFactory;
|
||||
_inputFormattersProvider = inputFormattersProvider;
|
||||
|
|
@ -39,6 +41,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
_modelValidationProviderProvider = modelValidationProviderProvider;
|
||||
_valueProviderFactoryProvider = valueProviderFactoryProvider;
|
||||
_actionBindingContextAccessor = actionBindingContextAccessor;
|
||||
_tempData = tempData;
|
||||
}
|
||||
|
||||
public int Order
|
||||
|
|
@ -63,7 +66,8 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
_modelBinderProvider,
|
||||
_modelValidationProviderProvider,
|
||||
_valueProviderFactoryProvider,
|
||||
_actionBindingContextAccessor);
|
||||
_actionBindingContextAccessor,
|
||||
_tempData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a set of data that persists only from one request to the next.
|
||||
/// </summary>
|
||||
public interface ITempDataDictionary : IDictionary<string, object>
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads the dictionary by using the registered <see cref="ITempDataProvider"/>.
|
||||
/// </summary>
|
||||
void Load();
|
||||
|
||||
/// <summary>
|
||||
/// Saves the dictionary by using the registered <see cref="ITempDataProvider"/>.
|
||||
/// </summary>
|
||||
void Save();
|
||||
|
||||
/// <summary>
|
||||
/// Marks all keys in the dictionary for retention.
|
||||
/// </summary>
|
||||
void Keep();
|
||||
|
||||
/// <summary>
|
||||
/// Marks the specified key in the dictionary for retention.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to retain in the dictionary.</param>
|
||||
void Keep(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that contains the element that is associated with the specified key,
|
||||
/// without marking the key for deletion.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the element to return.</param>
|
||||
/// <returns>An object that contains the element that is associated with the specified key.</returns>
|
||||
object Peek(string key);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for temporary-data providers that store data that is viewed on the next request.
|
||||
/// </summary>
|
||||
public interface ITempDataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads the temporary data.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="HttpContext"/>.</param>
|
||||
/// <returns>The temporary data.</returns>
|
||||
IDictionary<string, object> LoadTempData([NotNull] HttpContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the temporary data.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="HttpContext"/>.</param>
|
||||
/// <param name="values">The values to save.</param>
|
||||
void SaveTempData([NotNull] HttpContext context, IDictionary<string, object> values);
|
||||
}
|
||||
}
|
||||
|
|
@ -113,6 +113,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ITempDataDictionary TempData
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewContext.TempData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IHtmlEncoder HtmlEncoder { get; }
|
||||
|
||||
|
|
@ -450,7 +459,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
var view = viewEngineResult.View;
|
||||
using (view as IDisposable)
|
||||
{
|
||||
var viewContext = new ViewContext(ViewContext, view, newViewData, writer);
|
||||
var viewContext = new ViewContext(ViewContext, view, newViewData, TempData, writer);
|
||||
await viewEngineResult.View.RenderAsync(viewContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// </summary>
|
||||
ViewDataDictionary ViewData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current <see cref="ITempDataDictionary"/> instance.
|
||||
/// </summary>
|
||||
ITempDataDictionary TempData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IHtmlEncoder"/> to be used for encoding HTML.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Bson;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides session-state data to the current <see cref="ITempDataDictionary"/> object.
|
||||
/// </summary>
|
||||
public class SessionStateTempDataProvider : ITempDataProvider
|
||||
{
|
||||
private static JsonSerializer jsonSerializer = new JsonSerializer();
|
||||
private static string TempDataSessionStateKey = "__ControllerTempData";
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IDictionary<string, object> LoadTempData([NotNull] HttpContext context)
|
||||
{
|
||||
if (!IsSessionEnabled(context))
|
||||
{
|
||||
// Session middleware is not enabled. No-op
|
||||
return null;
|
||||
}
|
||||
|
||||
var tempDataDictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
var session = context.Session;
|
||||
byte[] value;
|
||||
|
||||
if (session != null && session.TryGetValue(TempDataSessionStateKey, out value))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(value))
|
||||
using (var writer = new BsonReader(memoryStream))
|
||||
{
|
||||
tempDataDictionary = jsonSerializer.Deserialize<Dictionary<string, object>>(writer);
|
||||
}
|
||||
|
||||
// If we got it from Session, remove it so that no other request gets it
|
||||
session.Remove(TempDataSessionStateKey);
|
||||
}
|
||||
|
||||
return tempDataDictionary;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void SaveTempData([NotNull] HttpContext context, IDictionary<string, object> values)
|
||||
{
|
||||
var hasValues = (values != null && values.Count > 0);
|
||||
if (hasValues)
|
||||
{
|
||||
// Accessing Session property will throw if the session middleware is not enabled.
|
||||
var session = context.Session;
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
using (var writer = new BsonWriter(memoryStream))
|
||||
{
|
||||
jsonSerializer.Serialize(writer, values);
|
||||
session[TempDataSessionStateKey] = memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
else if (IsSessionEnabled(context))
|
||||
{
|
||||
var session = context.Session;
|
||||
session.Remove(TempDataSessionStateKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsSessionEnabled(HttpContext context)
|
||||
{
|
||||
return context.GetFeature<ISessionFeature>() != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Hosting;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class TempDataDictionary : ITempDataDictionary
|
||||
{
|
||||
private Dictionary<string, object> _data;
|
||||
private bool _loaded;
|
||||
private readonly ITempDataProvider _provider;
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
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="provider">The <see cref="ITempDataProvider"/> used to Load and Save data.</param>
|
||||
public TempDataDictionary([NotNull] IHttpContextAccessor context, [NotNull] ITempDataProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
_loaded = false;
|
||||
_contextAccessor = context;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
return _data.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
return _data.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<object> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
return _data.Values;
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string, object>>.IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
return ((ICollection<KeyValuePair<string, object>>)_data).IsReadOnly;
|
||||
}
|
||||
}
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
Load();
|
||||
object value;
|
||||
if (TryGetValue(key, out value))
|
||||
{
|
||||
// Mark the key for deletion since it is read.
|
||||
_initialKeys.Remove(key);
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
Load();
|
||||
_data[key] = value;
|
||||
_initialKeys.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Keep()
|
||||
{
|
||||
Load();
|
||||
_retainedKeys.Clear();
|
||||
_retainedKeys.UnionWith(_data.Keys);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Keep(string key)
|
||||
{
|
||||
Load();
|
||||
_retainedKeys.Add(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Load()
|
||||
{
|
||||
if (_loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var providerDictionary = _provider.LoadTempData(_contextAccessor.HttpContext);
|
||||
_data = (providerDictionary != null)
|
||||
? new Dictionary<string, object>(providerDictionary, StringComparer.OrdinalIgnoreCase)
|
||||
: new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
_initialKeys = new HashSet<string>(_data.Keys, StringComparer.OrdinalIgnoreCase);
|
||||
_retainedKeys.Clear();
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Save()
|
||||
{
|
||||
if (!_loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Because it is not possible to delete while enumerating, a copy of the keys must be taken.
|
||||
// Use the size of the dictionary as an upper bound to avoid creating more than one copy of the keys.
|
||||
var removeCount = 0;
|
||||
var keys = new string[_data.Count];
|
||||
foreach (var entry in _data)
|
||||
{
|
||||
if (!_initialKeys.Contains(entry.Key) && !_retainedKeys.Contains(entry.Key))
|
||||
{
|
||||
keys[removeCount] = entry.Key;
|
||||
removeCount++;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < removeCount; i++)
|
||||
{
|
||||
_data.Remove(keys[i]);
|
||||
}
|
||||
|
||||
_provider.SaveTempData(_contextAccessor.HttpContext, _data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Peek(string key)
|
||||
{
|
||||
Load();
|
||||
object value;
|
||||
_data.TryGetValue(key, out value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public void Add(string key, object value)
|
||||
{
|
||||
Load();
|
||||
_data.Add(key, value);
|
||||
_initialKeys.Add(key);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Load();
|
||||
_data.Clear();
|
||||
_retainedKeys.Clear();
|
||||
_initialKeys.Clear();
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
Load();
|
||||
return _data.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool ContainsValue(object value)
|
||||
{
|
||||
Load();
|
||||
return _data.ContainsValue(value);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
Load();
|
||||
return new TempDataDictionaryEnumerator(this);
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
Load();
|
||||
_retainedKeys.Remove(key);
|
||||
_initialKeys.Remove(key);
|
||||
return _data.Remove(key);
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out object value)
|
||||
{
|
||||
Load();
|
||||
// Mark the key for deletion since it is read.
|
||||
_initialKeys.Remove(key);
|
||||
return _data.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int index)
|
||||
{
|
||||
Load();
|
||||
((ICollection<KeyValuePair<string, object>>)_data).CopyTo(array, index);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> keyValuePair)
|
||||
{
|
||||
Load();
|
||||
_initialKeys.Add(keyValuePair.Key);
|
||||
((ICollection<KeyValuePair<string, object>>)_data).Add(keyValuePair);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> keyValuePair)
|
||||
{
|
||||
Load();
|
||||
return ((ICollection<KeyValuePair<string, object>>)_data).Contains(keyValuePair);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> keyValuePair)
|
||||
{
|
||||
Load();
|
||||
_initialKeys.Remove(keyValuePair.Key);
|
||||
return ((ICollection<KeyValuePair<string, object>>)_data).Remove(keyValuePair);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
Load();
|
||||
return new TempDataDictionaryEnumerator(this);
|
||||
}
|
||||
|
||||
private sealed class TempDataDictionaryEnumerator : IEnumerator<KeyValuePair<string, object>>
|
||||
{
|
||||
private IEnumerator<KeyValuePair<string, object>> _enumerator;
|
||||
private TempDataDictionary _tempData;
|
||||
|
||||
public TempDataDictionaryEnumerator(TempDataDictionary tempData)
|
||||
{
|
||||
_tempData = tempData;
|
||||
_enumerator = _tempData._data.GetEnumerator();
|
||||
}
|
||||
|
||||
public KeyValuePair<string, object> Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var kvp = _enumerator.Current;
|
||||
// Mark the key for deletion since it is read.
|
||||
_tempData._initialKeys.Remove(kvp.Key);
|
||||
return kvp;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get { return Current; }
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
return _enumerator.MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_enumerator.Reset();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
_enumerator.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ITempDataDictionary"/> instance.
|
||||
/// </summary>
|
||||
public ITempDataDictionary TempData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ViewEngine"/>.
|
||||
/// </summary>
|
||||
|
|
@ -90,6 +95,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
context.ViewContext,
|
||||
view,
|
||||
ViewData ?? context.ViewContext.ViewData,
|
||||
TempData ?? context.ViewContext.TempData,
|
||||
context.Writer);
|
||||
|
||||
using (view as IDisposable)
|
||||
|
|
|
|||
|
|
@ -24,16 +24,19 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// <param name="actionContext">The <see cref="ActionContext"/>.</param>
|
||||
/// <param name="view">The <see cref="IView"/> being rendered.</param>
|
||||
/// <param name="viewData">The <see cref="ViewDataDictionary"/>.</param>
|
||||
/// <param name="tempData">The <see cref="ITempDataDictionary"/>.</param>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to render output to.</param>
|
||||
public ViewContext(
|
||||
[NotNull] ActionContext actionContext,
|
||||
[NotNull] IView view,
|
||||
[NotNull] ViewDataDictionary viewData,
|
||||
[NotNull] ITempDataDictionary tempData,
|
||||
[NotNull] TextWriter writer)
|
||||
: base(actionContext)
|
||||
{
|
||||
View = view;
|
||||
ViewData = viewData;
|
||||
TempData = tempData;
|
||||
Writer = writer;
|
||||
|
||||
_formContext = _defaultFormContext;
|
||||
|
|
@ -64,6 +67,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
View = view;
|
||||
ViewData = viewData;
|
||||
TempData = viewContext.TempData;
|
||||
Writer = writer;
|
||||
}
|
||||
|
||||
|
|
@ -135,6 +139,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ITempDataDictionary"/> instance.
|
||||
/// </summary>
|
||||
public ITempDataDictionary TempData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="TextWriter"/> used to write the output.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -105,7 +105,19 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
get
|
||||
{
|
||||
return (ViewContext == null) ? null : ViewContext.ViewBag;
|
||||
return ViewContext?.ViewBag;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ITempDataDictionary"/> from the <see cref="ViewContext"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Returns null if <see cref="ViewContext"/> is null.</remarks>
|
||||
public ITempDataDictionary TempData
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewContext?.TempData;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,6 +177,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
yield return describe.Singleton<IApiDescriptionGroupCollectionProvider,
|
||||
ApiDescriptionGroupCollectionProvider>();
|
||||
yield return describe.Transient<IApiDescriptionProvider, DefaultApiDescriptionProvider>();
|
||||
|
||||
// Temp Data
|
||||
yield return describe.Singleton<ITempDataProvider, SessionStateTempDataProvider>();
|
||||
yield return describe.Scoped<ITempDataDictionary, TempDataDictionary>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,30 @@ 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();
|
||||
|
|
@ -105,6 +129,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddInstance<IUrlHelper>(urlHelper);
|
||||
serviceCollection.AddInstance<ITempDataDictionary>(Mock.Of<ITempDataDictionary>());
|
||||
return serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
|||
var httpContext = new Mock<HttpContext>();
|
||||
var httpResponse = new Mock<HttpResponse>();
|
||||
httpContext.Setup(o => o.Response).Returns(httpResponse.Object);
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary)))
|
||||
.Returns(Mock.Of<ITempDataDictionary>());
|
||||
|
||||
var actionContext = new ActionContext(httpContext.Object,
|
||||
new RouteData(),
|
||||
|
|
@ -66,6 +68,32 @@ 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>();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
var httpContext = new Mock<HttpContext>();
|
||||
var httpResponse = new Mock<HttpResponse>();
|
||||
httpContext.Setup(o => o.Response).Returns(httpResponse.Object);
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary)))
|
||||
.Returns(Mock.Of<ITempDataDictionary>());
|
||||
|
||||
var actionContext = new ActionContext(httpContext.Object,
|
||||
new RouteData(),
|
||||
|
|
@ -69,6 +71,32 @@ 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());
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> RedirectToRouteData
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
||||
// Act
|
||||
await ViewExecutor.ExecuteAsync(view.Object, actionContext, viewData, contentType: null);
|
||||
await ViewExecutor.ExecuteAsync(view.Object, actionContext, viewData, null, contentType: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, memoryStream.ToArray());
|
||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
|
||||
// Act
|
||||
await ViewExecutor.ExecuteAsync(view, actionContext, viewData, contentType);
|
||||
await ViewExecutor.ExecuteAsync(view, actionContext, viewData, null, contentType);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(contentType, context.Response.ContentType);
|
||||
|
|
@ -120,7 +120,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
// Act
|
||||
await Record.ExceptionAsync(
|
||||
() => ViewExecutor.ExecuteAsync(view.Object, actionContext, viewData, contentType: null));
|
||||
() => ViewExecutor.ExecuteAsync(view.Object, actionContext, viewData, null, contentType: null));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedLength, memoryStream.Length);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,36 @@ 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<IFilter>(), 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<IFilter>(), 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()
|
||||
{
|
||||
|
|
@ -1929,12 +1959,18 @@ namespace Microsoft.AspNet.Mvc
|
|||
Assert.Same(input, contentResult.Value);
|
||||
}
|
||||
|
||||
private TestControllerActionInvoker CreateInvoker(IFilter filter, bool actionThrows = false)
|
||||
private TestControllerActionInvoker CreateInvoker(
|
||||
IFilter filter,
|
||||
bool actionThrows = false,
|
||||
ITempDataDictionary tempData = null)
|
||||
{
|
||||
return CreateInvoker(new[] { filter }, actionThrows);
|
||||
return CreateInvoker(new[] { filter }, actionThrows, tempData);
|
||||
}
|
||||
|
||||
private TestControllerActionInvoker CreateInvoker(IFilter[] filters, bool actionThrows = false)
|
||||
private TestControllerActionInvoker CreateInvoker(
|
||||
IFilter[] filters,
|
||||
bool actionThrows = false,
|
||||
ITempDataDictionary tempData = null)
|
||||
{
|
||||
var actionDescriptor = new ControllerActionDescriptor()
|
||||
{
|
||||
|
|
@ -1951,6 +1987,7 @@ 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;
|
||||
|
|
@ -1965,6 +2002,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
httpContext.SetupGet(c => c.Response).Returns(httpResponse);
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(mockFormattersProvider.Object);
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(ITempDataDictionary)))
|
||||
.Returns(tempData);
|
||||
httpResponse.Body = new MemoryStream();
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
|
|
@ -2012,7 +2051,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
new MockModelBinderProvider(),
|
||||
new MockModelValidatorProviderProvider(),
|
||||
new MockValueProviderFactoryProvider(),
|
||||
new MockScopedInstance<ActionBindingContext>());
|
||||
new MockScopedInstance<ActionBindingContext>(),
|
||||
tempData);
|
||||
|
||||
return invoker;
|
||||
}
|
||||
|
|
@ -2044,6 +2084,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
var context = new Mock<HttpContext>();
|
||||
context.SetupGet(c => c.Items)
|
||||
.Returns(new Dictionary<object, object>());
|
||||
context.Setup(c => c.RequestServices.GetService(typeof(ITempDataDictionary)))
|
||||
.Returns(new Mock<ITempDataDictionary>().Object);
|
||||
|
||||
var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor);
|
||||
|
||||
|
|
@ -2067,7 +2109,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
new MockModelBinderProvider() { ModelBinders = new List<IModelBinder>() { binder.Object } },
|
||||
new MockModelValidatorProviderProvider(),
|
||||
new MockValueProviderFactoryProvider(),
|
||||
new MockScopedInstance<ActionBindingContext>());
|
||||
new MockScopedInstance<ActionBindingContext>(),
|
||||
Mock.Of<ITempDataDictionary>());
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
|
@ -2164,7 +2207,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
IModelBinderProvider modelBinderProvider,
|
||||
IModelValidatorProviderProvider modelValidatorProviderProvider,
|
||||
IValueProviderFactoryProvider valueProviderFactoryProvider,
|
||||
IScopedInstance<ActionBindingContext> actionBindingContext)
|
||||
IScopedInstance<ActionBindingContext> actionBindingContext,
|
||||
ITempDataDictionary tempData)
|
||||
: base(
|
||||
actionContext,
|
||||
filterProvider,
|
||||
|
|
@ -2175,7 +2219,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
modelBinderProvider,
|
||||
modelValidatorProviderProvider,
|
||||
valueProviderFactoryProvider,
|
||||
actionBindingContext)
|
||||
actionBindingContext,
|
||||
tempData)
|
||||
{
|
||||
ControllerFactory = controllerFactory;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,16 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Hosting;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.AspNet.WebUtilities;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
#if DNX451
|
||||
using Moq;
|
||||
#endif
|
||||
|
|
@ -739,12 +740,13 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Controller_View_WithoutParameter_SetsResultNullViewNameAndNullViewDataModel()
|
||||
public void Controller_View_WithoutParameter_SetsResultNullViewNameAndNullViewDataModelAndSameTempData()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController()
|
||||
{
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()),
|
||||
};
|
||||
|
||||
// Act
|
||||
|
|
@ -754,16 +756,18 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
Assert.IsType<ViewResult>(actualViewResult);
|
||||
Assert.Null(actualViewResult.ViewName);
|
||||
Assert.Same(controller.ViewData, actualViewResult.ViewData);
|
||||
Assert.Same(controller.TempData, actualViewResult.TempData);
|
||||
Assert.Null(actualViewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Controller_View_WithParameterViewName_SetsResultViewNameAndNullViewDataModel()
|
||||
public void Controller_View_WithParameterViewName_SetsResultViewNameAndNullViewDataModelAndSameTempData()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController()
|
||||
{
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()),
|
||||
};
|
||||
|
||||
// Act
|
||||
|
|
@ -773,16 +777,18 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
Assert.IsType<ViewResult>(actualViewResult);
|
||||
Assert.Equal("CustomViewName", actualViewResult.ViewName);
|
||||
Assert.Same(controller.ViewData, actualViewResult.ViewData);
|
||||
Assert.Same(controller.TempData, actualViewResult.TempData);
|
||||
Assert.Null(actualViewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Controller_View_WithParameterViewModel_SetsResultNullViewNameAndViewDataModel()
|
||||
public void Controller_View_WithParameterViewModel_SetsResultNullViewNameAndViewDataModelAndSameTempData()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController()
|
||||
{
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()),
|
||||
};
|
||||
var model = new object();
|
||||
|
||||
|
|
@ -793,16 +799,18 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
Assert.IsType<ViewResult>(actualViewResult);
|
||||
Assert.Null(actualViewResult.ViewName);
|
||||
Assert.Same(controller.ViewData, actualViewResult.ViewData);
|
||||
Assert.Same(controller.TempData, actualViewResult.TempData);
|
||||
Assert.Same(model, actualViewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Controller_View_WithParameterViewNameAndViewModel_SetsResultViewNameAndViewDataModel()
|
||||
public void Controller_View_WithParameterViewNameAndViewModel_SetsResultViewNameAndViewDataModelAndSameTempData()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController()
|
||||
{
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()),
|
||||
};
|
||||
var model = new object();
|
||||
|
||||
|
|
@ -813,6 +821,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
Assert.IsType<ViewResult>(actualViewResult);
|
||||
Assert.Equal("CustomViewName", actualViewResult.ViewName);
|
||||
Assert.Same(controller.ViewData, actualViewResult.ViewData);
|
||||
Assert.Same(controller.TempData, actualViewResult.TempData);
|
||||
Assert.Same(model, actualViewResult.ViewData.Model);
|
||||
}
|
||||
|
||||
|
|
@ -1466,6 +1475,21 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
Assert.Equal("The 'BindingContext' property of 'Microsoft.AspNet.Mvc.Controller' must not be null.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_CanSetAndGetValues()
|
||||
{
|
||||
// Arrange
|
||||
var controller = GetController(null, null);
|
||||
var input = "Foo";
|
||||
|
||||
// Act
|
||||
controller.TempData["key"] = input;
|
||||
var result = controller.TempData["key"];
|
||||
|
||||
// Assert
|
||||
Assert.Equal(input, result);
|
||||
}
|
||||
|
||||
private static Controller GetController(IModelBinder binder, IValueProvider provider)
|
||||
{
|
||||
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
|
|
@ -1473,6 +1497,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
|
||||
var tempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>());
|
||||
|
||||
var bindingContext = new ActionBindingContext()
|
||||
{
|
||||
|
|
@ -1487,6 +1512,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
BindingContext = bindingContext,
|
||||
MetadataProvider = metadataProvider,
|
||||
ViewData = viewData,
|
||||
TempData = tempData,
|
||||
ObjectValidator = new DefaultObjectValidator(Mock.Of<IValidationExcludeFiltersProvider>(), metadataProvider)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Same(model, viewResult.ViewData.Model);
|
||||
Assert.Same(controller.ViewData, viewResult.ViewData);
|
||||
Assert.Same(controller.TempData, viewResult.TempData);
|
||||
|
||||
if (model != null)
|
||||
{
|
||||
|
|
@ -61,6 +62,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
Assert.NotNull(viewResult.ViewData);
|
||||
Assert.Same(model, viewResult.ViewData.Model);
|
||||
Assert.Same(controller.ViewData, viewResult.ViewData);
|
||||
Assert.Same(controller.TempData, viewResult.TempData);
|
||||
|
||||
if (model != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -281,6 +281,8 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
services
|
||||
.Setup(s => s.GetService(typeof(IScopedInstance<ActionBindingContext>)))
|
||||
.Returns(new MockScopedInstance<ActionBindingContext>());
|
||||
services.Setup(s => s.GetService(typeof(ITempDataDictionary)))
|
||||
.Returns(new Mock<ITempDataDictionary>().Object);
|
||||
return services.Object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
return new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
null,
|
||||
TextWriter.Null);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -881,6 +881,11 @@ Environment.NewLine;
|
|||
get { return _innerHelper.ViewData; }
|
||||
}
|
||||
|
||||
public ITempDataDictionary TempData
|
||||
{
|
||||
get { return _innerHelper.TempData; }
|
||||
}
|
||||
|
||||
public IHtmlEncoder HtmlEncoder
|
||||
{
|
||||
get { return _innerHelper.HtmlEncoder; }
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
new HtmlEncoder(),
|
||||
new UrlEncoder(),
|
||||
new JavaScriptStringEncoder());
|
||||
var viewContext = new ViewContext(actionContext, Mock.Of<IView>(), viewData, new StringWriter());
|
||||
var viewContext = new ViewContext(actionContext, Mock.Of<IView>(), viewData, null, new StringWriter());
|
||||
htmlHelper.Contextualize(viewContext);
|
||||
|
||||
return htmlHelper;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public void SettingViewData_AlsoUpdatesViewBag()
|
||||
{
|
||||
// Arrange (eventually passing null to these consturctors will throw)
|
||||
var context = new ViewContext(new ActionContext(null, null, null), view: null, viewData: null, writer: null);
|
||||
var context = new ViewContext(new ActionContext(null, null, null), view: null, viewData: null, tempData: null, writer: null);
|
||||
var originalViewData = context.ViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider());
|
||||
var replacementViewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider());
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class SessionStateTempDataProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void Load_NullSession_ReturnsEmptyDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var testProvider = new SessionStateTempDataProvider();
|
||||
|
||||
// Act
|
||||
var tempDataDictionary = testProvider.LoadTempData(
|
||||
GetHttpContext(session: null, sessionEnabled: true));
|
||||
|
||||
// Assert
|
||||
Assert.Empty(tempDataDictionary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Load_NonNullSession_NoSessionData_ReturnsEmptyDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var testProvider = new SessionStateTempDataProvider();
|
||||
|
||||
// Act
|
||||
var tempDataDictionary = testProvider.LoadTempData(
|
||||
GetHttpContext(Mock.Of<ISessionCollection>()));
|
||||
|
||||
// Assert
|
||||
Assert.Empty(tempDataDictionary);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_NullSession_NullDictionary_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var testProvider = new SessionStateTempDataProvider();
|
||||
|
||||
// Act & Assert (does not throw)
|
||||
testProvider.SaveTempData(GetHttpContext(session: null, sessionEnabled: false), null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_NullSession_EmptyDictionary_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var testProvider = new SessionStateTempDataProvider();
|
||||
|
||||
// Act & Assert (does not throw)
|
||||
testProvider.SaveTempData(
|
||||
GetHttpContext(session: null, sessionEnabled: false), new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_NullSession_NonEmptyDictionary_Throws()
|
||||
{
|
||||
// Arrange
|
||||
var testProvider = new SessionStateTempDataProvider();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
testProvider.SaveTempData(
|
||||
GetHttpContext(session: null, sessionEnabled: false),
|
||||
new Dictionary<string, object> { { "foo", "bar" } }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private HttpContext GetHttpContext(ISessionCollection session, bool sessionEnabled=true)
|
||||
{
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
if (session != null)
|
||||
{
|
||||
httpContext.Setup(h => h.Session).Returns(session);
|
||||
}
|
||||
else if (!sessionEnabled)
|
||||
{
|
||||
httpContext.Setup(h => h.Session).Throws<InvalidOperationException>();
|
||||
}
|
||||
if (sessionEnabled)
|
||||
{
|
||||
httpContext.Setup(h => h.GetFeature<ISessionFeature>()).Returns(Mock.Of<ISessionFeature>());
|
||||
}
|
||||
return httpContext.Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Hosting;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class TempDataDictionaryTest
|
||||
{
|
||||
[Fact]
|
||||
public void TempData_Load_CreatesEmptyDictionaryIfProviderReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
|
||||
// Act
|
||||
tempData.Load();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(tempData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_Save_RemovesKeysThatWereRead()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
tempData["Foo"] = "Foo";
|
||||
tempData["Bar"] = "Bar";
|
||||
|
||||
// Act
|
||||
var value = tempData["Foo"];
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.False(tempData.ContainsKey("Foo"));
|
||||
Assert.True(tempData.ContainsKey("Bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_EnumeratingDictionary_MarksKeysForDeletion()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
tempData["Foo"] = "Foo";
|
||||
tempData["Bar"] = "Bar";
|
||||
|
||||
// Act
|
||||
var enumerator = tempData.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var value = enumerator.Current;
|
||||
}
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.False(tempData.ContainsKey("Foo"));
|
||||
Assert.False(tempData.ContainsKey("Bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_TryGetValue_MarksKeyForDeletion()
|
||||
{
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
object value;
|
||||
tempData["Foo"] = "Foo";
|
||||
|
||||
// Act
|
||||
tempData.TryGetValue("Foo", out value);
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.False(tempData.ContainsKey("Foo"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_Keep_RetainsAllKeysWhenSavingDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
tempData["Foo"] = "Foo";
|
||||
tempData["Bar"] = "Bar";
|
||||
|
||||
// Act
|
||||
tempData.Keep();
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.True(tempData.ContainsKey("Foo"));
|
||||
Assert.True(tempData.ContainsKey("Bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_Keep_RetainsSpecificKeysWhenSavingDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
tempData["Foo"] = "Foo";
|
||||
tempData["Bar"] = "Bar";
|
||||
|
||||
// Act
|
||||
var foo = tempData["Foo"];
|
||||
var bar = tempData["Bar"];
|
||||
tempData.Keep("Foo");
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.True(tempData.ContainsKey("Foo"));
|
||||
Assert.False(tempData.ContainsKey("Bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_Peek_DoesNotMarkKeyForDeletion()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
tempData["Bar"] = "barValue";
|
||||
|
||||
// Act
|
||||
var value = tempData.Peek("bar");
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("barValue", value);
|
||||
Assert.True(tempData.ContainsKey("Bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_CompareIsOrdinalIgnoreCase()
|
||||
{
|
||||
// Arrange
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
var item = new object();
|
||||
|
||||
// Act
|
||||
tempData["Foo"] = item;
|
||||
var value = tempData["FOO"];
|
||||
|
||||
// Assert
|
||||
Assert.Same(item, value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_LoadAndSaveAreCaseInsensitive()
|
||||
{
|
||||
// Arrange
|
||||
var data = new Dictionary<string, object>();
|
||||
data["Foo"] = "Foo";
|
||||
data["Bar"] = "Bar";
|
||||
var provider = new TestTempDataProvider(data);
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), provider);
|
||||
|
||||
// Act
|
||||
tempData.Load();
|
||||
var value = tempData["FOO"];
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.False(tempData.ContainsKey("foo"));
|
||||
Assert.True(tempData.ContainsKey("bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TempData_RemovalOfKeysAreCaseInsensitive()
|
||||
{
|
||||
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new NullTempDataProvider());
|
||||
object fooValue;
|
||||
tempData["Foo"] = "Foo";
|
||||
tempData["Bar"] = "Bar";
|
||||
|
||||
// Act
|
||||
tempData.TryGetValue("foo", out fooValue);
|
||||
var barValue = tempData["bar"];
|
||||
tempData.Save();
|
||||
|
||||
// Assert
|
||||
Assert.False(tempData.ContainsKey("Foo"));
|
||||
Assert.False(tempData.ContainsKey("Boo"));
|
||||
}
|
||||
|
||||
private class NullTempDataProvider : ITempDataProvider
|
||||
{
|
||||
public IDictionary<string, object> LoadTempData([NotNull]HttpContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SaveTempData([NotNull]HttpContext context, IDictionary<string, object> values)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestTempDataProvider : ITempDataProvider
|
||||
{
|
||||
private IDictionary<string, object> _data;
|
||||
|
||||
public TestTempDataProvider(IDictionary<string, object> data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> LoadTempData([NotNull]HttpContext context)
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public void SaveTempData([NotNull]HttpContext context, IDictionary<string, object> values)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static IHttpContextAccessor GetHttpContextAccessor()
|
||||
{
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
var httpContextAccessor = new Mock<IHttpContextAccessor>();
|
||||
httpContextAccessor.Setup(h => h.HttpContext).Returns(httpContext.Object);
|
||||
return httpContextAccessor.Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, TextWriter.Null);
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, writer);
|
||||
return viewComponentContext;
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, TextWriter.Null);
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||
var writer = new StreamWriter(stream) { AutoFlush = true };
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, writer);
|
||||
return viewComponentContext;
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
private static ViewComponentContext GetViewComponentContext(IView view, ViewDataDictionary viewData)
|
||||
{
|
||||
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, TextWriter.Null);
|
||||
var viewContext = new ViewContext(actionContext, view, viewData, null, TextWriter.Null);
|
||||
var viewComponentContext = new ViewComponentContext(typeof(object).GetTypeInfo(), viewContext, TextWriter.Null);
|
||||
return viewComponentContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
public class TempDataTest
|
||||
{
|
||||
private readonly IServiceProvider _services = TestHelper.CreateServices("TempDataWebSite");
|
||||
private readonly Action<IApplicationBuilder> _app = new TempDataWebSite.Startup().Configure;
|
||||
|
||||
[Fact]
|
||||
public async Task ViewRendersTempData()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
var nameValueCollection = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string,string>("value", "Foo"),
|
||||
};
|
||||
var content = new FormUrlEncodedContent(nameValueCollection);
|
||||
|
||||
// Act
|
||||
var response = await client.PostAsync("http://localhost/Home/DisplayTempData", content);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Foo", body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,6 +48,7 @@
|
|||
"RoutingWebSite": "1.0.0",
|
||||
"TagHelperSample.Web": "1.0.0",
|
||||
"TagHelpersWebSite": "1.0.0",
|
||||
"TempDataWebSite": "1.0.0",
|
||||
"UrlHelperWebSite": "1.0.0",
|
||||
"ValidationWebSite": "1.0.0",
|
||||
"ValueProvidersWebSite": "1.0.0",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var viewContext = new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
// Act
|
||||
|
|
@ -73,6 +74,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var viewContext = new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
// Act and Assert
|
||||
|
|
@ -114,6 +116,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var viewContext = new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
viewData,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
// Act
|
||||
|
|
@ -151,6 +154,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var viewContext = new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
viewData,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
// Act
|
||||
|
|
@ -185,6 +189,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var viewContext = new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
viewData,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
actionContext,
|
||||
view: Mock.Of<IView>(),
|
||||
viewData: viewData,
|
||||
tempData: Mock.Of<ITempDataDictionary>(),
|
||||
writer: new StringWriter());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var viewContext = new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
viewData,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
return new TestRazorPage
|
||||
|
|
|
|||
|
|
@ -816,6 +816,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
actionContext,
|
||||
Mock.Of<IView>(),
|
||||
null,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
writer);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1023,6 +1023,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
actionContext,
|
||||
view,
|
||||
new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
new StringWriter());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -756,6 +756,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
return new ViewContext(actionContext,
|
||||
Mock.Of<IView>(),
|
||||
new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -441,6 +441,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
actionContext,
|
||||
Mock.Of<IView>(),
|
||||
new ViewDataDictionary(new TestModelMetadataProvider()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -371,7 +371,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var viewData = new ViewDataDictionary(metadataProvider);
|
||||
var viewContext = new ViewContext(actionContext, Mock.Of<IView>(), viewData, TextWriter.Null);
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
Mock.Of<IView>(),
|
||||
viewData,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
return viewContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -462,7 +462,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var viewData = new ViewDataDictionary(metadataProvider);
|
||||
var viewContext = new ViewContext(actionContext, Mock.Of<IView>(), viewData, TextWriter.Null);
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
Mock.Of<IView>(),
|
||||
viewData,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
return viewContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
Model = model,
|
||||
};
|
||||
var viewContext = new ViewContext(actionContext, Mock.Of<IView>(), viewData, TextWriter.Null);
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
Mock.Of<IView>(),
|
||||
viewData,
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
|
||||
return viewContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
Mock.Of<IView>(),
|
||||
new ViewDataDictionary(
|
||||
new EmptyModelMetadataProvider()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ Parameter name: value",
|
|||
Mock.Of<IView>(),
|
||||
new ViewDataDictionary(
|
||||
new EmptyModelMetadataProvider()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace ModelBindingWebSite.Controllers
|
|||
{
|
||||
_activated = true;
|
||||
var viewData = new ViewDataDictionary<Person>(ViewData);
|
||||
var context = new ViewContext(ActionContext, new TestView(), viewData, TextWriter.Null);
|
||||
var context = new ViewContext(ActionContext, new TestView(), viewData, null, TextWriter.Null);
|
||||
((ICanHasViewContext)PersonHelper).Contextualize(context);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace TempDataWebSite.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult DisplayTempData(string value)
|
||||
{
|
||||
TempData["key"] = value;
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace TempDataWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
var configuration = app.GetTestConfiguration();
|
||||
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddCachingServices();
|
||||
services.AddSessionServices();
|
||||
services.AddMvc(configuration);
|
||||
});
|
||||
|
||||
app.UseInMemorySession();
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>8aeb631e-ab74-4d2e-83fb-8931ee10d9d3</ProjectGuid>
|
||||
<RootNamespace>TempDataWebSite</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>28690</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1 @@
|
|||
@TempData["key"]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Hello</title>
|
||||
</head>
|
||||
<body>
|
||||
Hello
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"commands": {
|
||||
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
|
||||
"kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5000"
|
||||
},
|
||||
"dependencies": {
|
||||
"Kestrel": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Session": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": { },
|
||||
"dnxcore50": { }
|
||||
},
|
||||
"webroot": "wwwroot"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
TempDataWebSite
|
||||
===
|
||||
|
||||
This web site illustrates use cases of TempData.
|
||||
|
|
@ -0,0 +1 @@
|
|||
HelloWorld
|
||||
Loading…
Reference in New Issue