Add Items bag to TagHelperContext.

- Add a an Item properties on TagHelperExecutionContext to propagate to the TagHelperContext.
- Updated TagHelperScopeManager to create CopyOnWriteDictionary item bags for created TagHelperExecutionContexts.

#238
This commit is contained in:
N. Taylor Mullen 2015-02-13 15:31:23 -08:00
parent 23e6264715
commit b95e73e2b0
10 changed files with 76 additions and 36 deletions

View File

@ -1,12 +0,0 @@
// 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;
namespace Microsoft.AspNet.Razor.Runtime
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
internal sealed class NotNullAttribute : Attribute
{
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@ -18,15 +19,19 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// Instantiates a new <see cref="TagHelperContext"/>.
/// </summary>
/// <param name="allAttributes">Every attribute associated with the current HTML element.</param>
/// <param name="items">Collection of items used to communicate with other <see cref="ITagHelper"/>s.</param>
/// <param name="uniqueId">The unique identifier for the source element this <see cref="TagHelperContext" />
/// applies to.</param>
/// <param name="getChildContentAsync">A delegate used to execute and retrieve the rendered child content
/// asynchronously.</param>
public TagHelperContext([NotNull] IDictionary<string, object> allAttributes,
[NotNull] string uniqueId,
[NotNull] Func<Task<string>> getChildContentAsync)
public TagHelperContext(
[NotNull] IDictionary<string, object> allAttributes,
[NotNull] IDictionary<object, object> items,
[NotNull] string uniqueId,
[NotNull] Func<Task<string>> getChildContentAsync)
{
AllAttributes = allAttributes;
Items = items;
UniqueId = uniqueId;
_getChildContentAsync = getChildContentAsync;
}
@ -36,6 +41,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary>
public IDictionary<string, object> AllAttributes { get; }
/// <summary>
/// Gets the collection of items used to communicate with other <see cref="ITagHelper"/>s.
/// </summary>
/// <remarks>
/// This <see cref="IDictionary{object, object}"/> is copy-on-write in order to ensure items added to this
/// collection are visible only to other <see cref="ITagHelper"/>s targeting child elements.
/// </remarks>
public IDictionary<object, object> Items { get; }
/// <summary>
/// An identifier unique to the HTML element this context is for.
/// </summary>

View File

@ -9,6 +9,7 @@ using System.Text.RegularExpressions;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{

View File

@ -2,9 +2,11 @@
// 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 System.IO;
using System.Threading.Tasks;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@ -25,6 +27,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
internal TagHelperExecutionContext(string tagName, bool selfClosing)
: this(tagName,
selfClosing,
items: new Dictionary<object, object>(),
uniqueId: string.Empty,
executeChildContentAsync: async () => await Task.FromResult(result: true),
startWritingScope: () => { },
@ -37,18 +40,21 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary>
/// <param name="tagName">The HTML tag name in the Razor source.</param>
/// <param name="selfClosing">
/// <see cref="bool"/> indicating whether or not the tag in the Razor source was self-closing.
/// </param>
/// <see cref="bool"/> indicating whether or not the tag in the Razor source was self-closing.</param>
/// <param name="items">The collection of items used to communicate with other
/// <see cref="ITagHelper"/>s</param>
/// <param name="uniqueId">An identifier unique to the HTML element this context is for.</param>
/// <param name="executeChildContentAsync">A delegate used to execute the child content asynchronously.</param>
/// <param name="startWritingScope">A delegate used to start a writing scope in a Razor page.</param>
/// <param name="endWritingScope">A delegate used to end a writing scope in a Razor page.</param>
public TagHelperExecutionContext([NotNull] string tagName,
bool selfClosing,
[NotNull] string uniqueId,
[NotNull] Func<Task> executeChildContentAsync,
[NotNull] Action startWritingScope,
[NotNull] Func<TextWriter> endWritingScope)
public TagHelperExecutionContext(
[NotNull] string tagName,
bool selfClosing,
[NotNull] IDictionary<object, object> items,
[NotNull] string uniqueId,
[NotNull] Func<Task> executeChildContentAsync,
[NotNull] Action startWritingScope,
[NotNull] Func<TextWriter> endWritingScope)
{
_tagHelpers = new List<ITagHelper>();
_executeChildContentAsync = executeChildContentAsync;
@ -59,6 +65,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
AllAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
HTMLAttributes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
TagName = tagName;
Items = items;
UniqueId = uniqueId;
}
@ -78,6 +85,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
}
/// <summary>
/// Gets the collection of items used to communicate with other <see cref="ITagHelper"/>s.
/// </summary>
public IDictionary<object, object> Items { get; }
/// <summary>
/// HTML attributes.
/// </summary>

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Text;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{

View File

@ -3,6 +3,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@ -22,6 +23,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
var tagHelperContext = new TagHelperContext(
executionContext.AllAttributes,
executionContext.Items,
executionContext.UniqueId,
executionContext.GetChildContentAsync);
var tagHelperOutput = new TagHelperOutput(executionContext.TagName, executionContext.HTMLAttributes)

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@ -35,19 +36,36 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <param name="startWritingScope">A delegate used to start a writing scope in a Razor page.</param>
/// <param name="endWritingScope">A delegate used to end a writing scope in a Razor page.</param>
/// <returns>A <see cref="TagHelperExecutionContext"/> to use.</returns>
public TagHelperExecutionContext Begin([NotNull] string tagName,
bool selfClosing,
[NotNull] string uniqueId,
[NotNull] Func<Task> executeChildContentAsync,
[NotNull] Action startWritingScope,
[NotNull] Func<TextWriter> endWritingScope)
public TagHelperExecutionContext Begin(
[NotNull] string tagName,
bool selfClosing,
[NotNull] string uniqueId,
[NotNull] Func<Task> executeChildContentAsync,
[NotNull] Action startWritingScope,
[NotNull] Func<TextWriter> endWritingScope)
{
var executionContext = new TagHelperExecutionContext(tagName,
selfClosing,
uniqueId,
executeChildContentAsync,
startWritingScope,
endWritingScope);
IDictionary<object, object> items;
// If we're not wrapped by another TagHelper, then there will not be a parentExecutionContext.
if (_executionScopes.Count > 0)
{
items = new CopyOnWriteDictionary<object, object>(
_executionScopes.Peek().Items,
comparer: EqualityComparer<object>.Default);
}
else
{
items = new Dictionary<object, object>();
}
var executionContext = new TagHelperExecutionContext(
tagName,
selfClosing,
items,
uniqueId,
executeChildContentAsync,
startWritingScope,
endWritingScope);
_executionScopes.Push(executionContext);

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Text;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{

View File

@ -2,7 +2,9 @@
"description": "Runtime components for rendering Razor pages.",
"version": "4.0.0-*",
"dependencies": {
"Microsoft.AspNet.Razor": "4.0.0-*"
"Microsoft.AspNet.Razor": "4.0.0-*",
"Microsoft.Framework.CopyOnWriteDictionary.Internal": { "type": "build", "version": "1.0.0-*" },
"Microsoft.Framework.NotNullAttribute.Internal": { "type": "build", "version": "1.0.0-*" }
},
"frameworks": {
"net45": { },