Clean up remaining `HtmlString` usage
- #3122 and #3123 (5 of 5) - avoid concatenating values and wrapping them in an `HtmlString` - switch from `string.Format()` to `AppendHtml()` in `LinkTagHelper` - simplify `RazorPage` and `TagHelperContentExtensions` e.g. don't use a `TagHelperContentWrapperTextWriter` - add some special cases in `UrlResolutionTagHelper` - add `TagBuilder` and `StringHtmlContent` special cases to avoid `StringWriter` use when value is an `HtmlString` - move `HtmlTextWriter` optimizations a bit lower and add missing checks for that type nits: - correct comments that incorrectly mention `HtmlString`s - update comments in `JavaScriptStringArrayEncoder`
This commit is contained in:
parent
dd774366f6
commit
1f76b3c7b7
|
|
@ -602,22 +602,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
if (!_tagHelperAttributeInfo.Suppressed)
|
||||
{
|
||||
HtmlString htmlString;
|
||||
|
||||
if (_valueBuffer != null)
|
||||
{
|
||||
using (var stringWriter = new StringWriter())
|
||||
{
|
||||
_valueBuffer.Content.WriteTo(stringWriter, HtmlEncoder);
|
||||
htmlString = new HtmlString(stringWriter.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
htmlString = HtmlString.Empty;
|
||||
}
|
||||
|
||||
executionContext.AddHtmlAttribute(_tagHelperAttributeInfo.Name, htmlString);
|
||||
executionContext.AddHtmlAttribute(
|
||||
_tagHelperAttributeInfo.Name,
|
||||
_valueBuffer?.Content ?? HtmlString.Empty);
|
||||
_valueBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -843,7 +831,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// content to the <see cref="HttpResponse.Body"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task{HtmlString}"/> that represents the asynchronous flush operation and on
|
||||
/// completion returns a <see cref="HtmlString.Empty"/>.</returns>
|
||||
/// completion returns <see cref="HtmlString.Empty"/>.</returns>
|
||||
/// <remarks>The value returned is a token value that allows FlushAsync to work directly in an HTML
|
||||
/// section. However the value does not represent the rendered content.
|
||||
/// This method also writes out headers, so any modifications to headers must be done before
|
||||
|
|
@ -936,7 +924,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <summary>
|
||||
/// Sets antiforgery cookie and X-Frame-Options header on the response.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="HtmlString"/> that returns a <see cref="HtmlString.Empty"/>.</returns>
|
||||
/// <returns><see cref="HtmlString.Empty"/>.</returns>
|
||||
/// <remarks> Call this method to send antiforgery cookie token and X-Frame-Options header to client
|
||||
/// before <see cref="FlushAsync"/> flushes the headers. </remarks>
|
||||
public virtual HtmlString SetAntiforgeryCookieAndHeader()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
|
|
@ -160,26 +162,45 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
{
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
string resolvedUrl;
|
||||
|
||||
var stringValue = attribute.Value as string;
|
||||
if (stringValue != null)
|
||||
{
|
||||
if (TryResolveUrl(stringValue, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
|
||||
string resolvedUrl;
|
||||
if (TryResolveUrl(stringValue, resolvedUrl: out resolvedUrl))
|
||||
{
|
||||
attribute.Value = resolvedUrl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var htmlStringValue = attribute.Value as HtmlString;
|
||||
if (htmlStringValue != null &&
|
||||
TryResolveUrl(
|
||||
htmlStringValue.ToString(),
|
||||
encodeWebRoot: true,
|
||||
resolvedUrl: out resolvedUrl))
|
||||
var htmlContent = attribute.Value as IHtmlContent;
|
||||
if (htmlContent != null)
|
||||
{
|
||||
attribute.Value = new HtmlString(resolvedUrl);
|
||||
var htmlString = htmlContent as HtmlString;
|
||||
if (htmlString != null)
|
||||
{
|
||||
// No need for a StringWriter in this case.
|
||||
stringValue = htmlString.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
htmlContent.WriteTo(writer, HtmlEncoder);
|
||||
stringValue = writer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
IHtmlContent resolvedUrl;
|
||||
if (TryResolveUrl(stringValue, resolvedUrl: out resolvedUrl))
|
||||
{
|
||||
attribute.Value = resolvedUrl;
|
||||
}
|
||||
else if (htmlString == null)
|
||||
{
|
||||
// Not a ~/ URL. Just avoid re-encoding the attribute value later.
|
||||
attribute.Value = new HtmlString(stringValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -190,14 +211,12 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
/// Tries to resolve the given <paramref name="url"/> value relative to the application's 'webroot' setting.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to resolve.</param>
|
||||
/// <param name="encodeWebRoot">If <c>true</c>, will HTML encode the expansion of '~/'.</param>
|
||||
/// <param name="resolvedUrl">Absolute URL beginning with the application's virtual root. <c>null</c> if
|
||||
/// <paramref name="url"/> could not be resolved.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="url"/> could be resolved; <c>false</c> otherwise.</returns>
|
||||
protected bool TryResolveUrl(string url, bool encodeWebRoot, out string resolvedUrl)
|
||||
protected bool TryResolveUrl(string url, out string resolvedUrl)
|
||||
{
|
||||
resolvedUrl = null;
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -205,42 +224,93 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
|
||||
var trimmedUrl = url.Trim(ValidAttributeWhitespaceChars);
|
||||
|
||||
// Before doing more work, ensure that the URL we're looking at is app relative.
|
||||
// Before doing more work, ensure that the URL we're looking at is app-relative.
|
||||
if (trimmedUrl.Length >= 2 && trimmedUrl[0] == '~' && trimmedUrl[1] == '/')
|
||||
{
|
||||
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
|
||||
var appRelativeUrl = urlHelper.Content(trimmedUrl);
|
||||
|
||||
if (encodeWebRoot)
|
||||
{
|
||||
var postTildeSlashUrlValue = trimmedUrl.Substring(2);
|
||||
|
||||
if (!appRelativeUrl.EndsWith(postTildeSlashUrlValue, StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatCouldNotResolveApplicationRelativeUrl_TagHelper(
|
||||
url,
|
||||
nameof(IUrlHelper),
|
||||
nameof(IUrlHelper.Content),
|
||||
"removeTagHelper",
|
||||
typeof(UrlResolutionTagHelper).FullName,
|
||||
typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly.GetName().Name));
|
||||
}
|
||||
|
||||
var applicationPath = appRelativeUrl.Substring(0, appRelativeUrl.Length - postTildeSlashUrlValue.Length);
|
||||
var encodedApplicationPath = HtmlEncoder.Encode(applicationPath);
|
||||
|
||||
resolvedUrl = string.Concat(encodedApplicationPath, postTildeSlashUrlValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
resolvedUrl = appRelativeUrl;
|
||||
}
|
||||
resolvedUrl = urlHelper.Content(trimmedUrl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to resolve the given <paramref name="url"/> value relative to the application's 'webroot' setting.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to resolve.</param>
|
||||
/// <param name="resolvedUrl">
|
||||
/// Absolute URL beginning with the application's virtual root. <c>null</c> if <paramref name="url"/> could
|
||||
/// not be resolved.
|
||||
/// </param>
|
||||
/// <returns><c>true</c> if the <paramref name="url"/> could be resolved; <c>false</c> otherwise.</returns>
|
||||
protected bool TryResolveUrl(string url, out IHtmlContent resolvedUrl)
|
||||
{
|
||||
resolvedUrl = null;
|
||||
if (url == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var trimmedUrl = url.Trim(ValidAttributeWhitespaceChars);
|
||||
|
||||
// Before doing more work, ensure that the URL we're looking at is app-relative.
|
||||
if (trimmedUrl.Length >= 2 && trimmedUrl[0] == '~' && trimmedUrl[1] == '/')
|
||||
{
|
||||
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
|
||||
var appRelativeUrl = urlHelper.Content(trimmedUrl);
|
||||
var postTildeSlashUrlValue = trimmedUrl.Substring(2);
|
||||
|
||||
if (!appRelativeUrl.EndsWith(postTildeSlashUrlValue, StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatCouldNotResolveApplicationRelativeUrl_TagHelper(
|
||||
url,
|
||||
nameof(IUrlHelper),
|
||||
nameof(IUrlHelper.Content),
|
||||
"removeTagHelper",
|
||||
typeof(UrlResolutionTagHelper).FullName,
|
||||
typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly.GetName().Name));
|
||||
}
|
||||
|
||||
resolvedUrl = new EncodeFirstSegmentContent(
|
||||
appRelativeUrl,
|
||||
appRelativeUrl.Length - postTildeSlashUrlValue.Length,
|
||||
postTildeSlashUrlValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private class EncodeFirstSegmentContent : IHtmlContent
|
||||
{
|
||||
private readonly string _firstSegment;
|
||||
private readonly int _firstSegmentLength;
|
||||
private readonly string _secondSegment;
|
||||
|
||||
public EncodeFirstSegmentContent(string firstSegment, int firstSegmentLength, string secondSegment)
|
||||
{
|
||||
_firstSegment = firstSegment;
|
||||
_firstSegmentLength = firstSegmentLength;
|
||||
_secondSegment = secondSegment;
|
||||
}
|
||||
|
||||
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||
{
|
||||
var htmlTextWriter = writer as HtmlTextWriter;
|
||||
if (htmlTextWriter != null)
|
||||
{
|
||||
htmlTextWriter.Write(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Encode(writer, _firstSegment, 0, _firstSegmentLength);
|
||||
writer.Write(_secondSegment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
// Load the JavaScript from embedded resource
|
||||
using (var resourceStream = getManifestResourceStream(key))
|
||||
{
|
||||
Debug.Assert(resourceStream != null, "Embedded resource missing. Ensure 'prebuild' script has run.");
|
||||
Debug.Assert(
|
||||
resourceStream != null,
|
||||
"Embedded resource missing. Ensure 'prebuild' script has run.");
|
||||
|
||||
using (var streamReader = new StreamReader(resourceStream))
|
||||
{
|
||||
|
|
@ -49,14 +51,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static string PrepareFormatString(string input)
|
||||
{
|
||||
// Replace unescaped/escaped chars with their equivalent
|
||||
return input.Replace("{", "{{")
|
||||
.Replace("}", "}}")
|
||||
.Replace("[[[", "{")
|
||||
.Replace("]]]", "}");
|
||||
// Remove final ");". Those characters are in the file only to allow minification.
|
||||
return input.Substring(0, input.Length - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,34 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Methods for encoding <see cref="IEnumerable{string}"/> for use as a JavaScript array literal.
|
||||
/// Methods for encoding <c>string[]</c>s for use as a JavaScript array literal.
|
||||
/// </summary>
|
||||
public static class JavaScriptStringArrayEncoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Encodes a .NET string array for safe use as a JavaScript array literal, including inline in an HTML file.
|
||||
/// Encodes a <c>string[]</c> for safe use as a JavaScript array literal in many contexts, including
|
||||
/// inline in an HTML file.
|
||||
/// </summary>
|
||||
public static string Encode(JavaScriptEncoder encoder, string[] values)
|
||||
{
|
||||
var writer = new StringWriter();
|
||||
|
||||
var firstAdded = false;
|
||||
|
||||
writer.Write('[');
|
||||
|
||||
// Perf: Avoid allocating enumerator
|
||||
var firstAdded = false;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
if (firstAdded)
|
||||
{
|
||||
writer.Write(',');
|
||||
}
|
||||
|
||||
writer.Write('"');
|
||||
encoder.Encode(writer, values[i]);
|
||||
writer.Write('"');
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ using Microsoft.AspNet.Mvc.Rendering;
|
|||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
|
||||
using Microsoft.AspNet.Mvc.TagHelpers.Logging;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -287,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
if (mode == Mode.Fallback)
|
||||
{
|
||||
string resolvedUrl;
|
||||
if (TryResolveUrl(FallbackHref, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
|
||||
if (TryResolveUrl(FallbackHref, resolvedUrl: out resolvedUrl))
|
||||
{
|
||||
FallbackHref = resolvedUrl;
|
||||
}
|
||||
|
|
@ -350,16 +349,17 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Build the <script /> tag that checks the effective style of <meta /> tag above and renders the extra
|
||||
// <link /> tag to load the fallback stylesheet if the test CSS property value is found to be false,
|
||||
// indicating that the primary stylesheet failed to load.
|
||||
// GetEmbeddedJavaScript returns JavaScript to which we add '"{0}","{1}",{2});'
|
||||
builder
|
||||
.AppendHtml("<script>")
|
||||
.AppendHtml(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
JavaScriptResources.GetEmbeddedJavaScript(FallbackJavaScriptResourceName),
|
||||
JavaScriptEncoder.Encode(FallbackTestProperty),
|
||||
JavaScriptEncoder.Encode(FallbackTestValue),
|
||||
JavaScriptStringArrayEncoder.Encode(JavaScriptEncoder, fallbackHrefs)))
|
||||
.AppendHtml("</script>");
|
||||
.AppendHtml(JavaScriptResources.GetEmbeddedJavaScript(FallbackJavaScriptResourceName))
|
||||
.AppendHtml("\"")
|
||||
.AppendHtml(JavaScriptEncoder.Encode(FallbackTestProperty))
|
||||
.AppendHtml("\",\"")
|
||||
.AppendHtml(JavaScriptEncoder.Encode(FallbackTestValue))
|
||||
.AppendHtml("\",")
|
||||
.AppendHtml(JavaScriptStringArrayEncoder.Encode(JavaScriptEncoder, fallbackHrefs))
|
||||
.AppendHtml(");</script>");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -410,7 +410,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
builder
|
||||
.AppendHtml(attribute.Name)
|
||||
.AppendHtml("=\"")
|
||||
.Append(HtmlEncoder, ViewContext.Writer.Encoding, attributeValue)
|
||||
.Append(HtmlEncoder, attributeValue)
|
||||
.AppendHtml("\" ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
if (mode == Mode.Fallback)
|
||||
{
|
||||
string resolvedUrl;
|
||||
if (TryResolveUrl(FallbackSrc, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
|
||||
if (TryResolveUrl(FallbackSrc, resolvedUrl: out resolvedUrl))
|
||||
{
|
||||
FallbackSrc = resolvedUrl;
|
||||
}
|
||||
|
|
@ -418,10 +418,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
}
|
||||
else
|
||||
{
|
||||
// HTML-encoded the given value if necessary.
|
||||
// HTML-encode the given value if necessary.
|
||||
content
|
||||
.AppendHtml("=\"")
|
||||
.Append(HtmlEncoder, ViewContext.Writer.Encoding, value)
|
||||
.Append(HtmlEncoder, value)
|
||||
.AppendHtml("\"");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||
|
|
@ -20,7 +20,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
/// </summary>
|
||||
/// <param name="content">The <see cref="TagHelperContent"/> to write to.</param>
|
||||
/// <param name="encoder">The <see cref="HtmlEncoder"/> to use when encoding <paramref name="value"/>.</param>
|
||||
/// <param name="encoding">The character encoding in which the <paramref name="value"/> is written.</param>
|
||||
/// <param name="value">The <see cref="object"/> to write.</param>
|
||||
/// <returns><paramref name="content"/> after the write operation has completed.</returns>
|
||||
/// <remarks>
|
||||
|
|
@ -29,11 +28,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
/// For all other types, the encoded result of <see cref="object.ToString"/>
|
||||
/// is written to the <paramref name="content"/>.
|
||||
/// </remarks>
|
||||
public static TagHelperContent Append(
|
||||
this TagHelperContent content,
|
||||
HtmlEncoder encoder,
|
||||
Encoding encoding,
|
||||
object value)
|
||||
public static TagHelperContent Append(this TagHelperContent content, HtmlEncoder encoder, object value)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
|
|
@ -45,25 +40,34 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
throw new ArgumentNullException(nameof(encoder));
|
||||
}
|
||||
|
||||
if (encoding == null)
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(encoding));
|
||||
// No real action but touch content to ensure IsModified is true.
|
||||
content.Append((string)null);
|
||||
return content;
|
||||
}
|
||||
|
||||
using (var writer = new TagHelperContentWrapperTextWriter(encoding, content))
|
||||
string stringValue;
|
||||
var htmlString = value as HtmlString;
|
||||
if (htmlString != null)
|
||||
{
|
||||
// No need for a StringWriter in this case.
|
||||
stringValue = htmlString.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var stringWriter = new StringWriter())
|
||||
{
|
||||
RazorPage.WriteTo(stringWriter, encoder, value);
|
||||
|
||||
// In this case the text likely came directly from the Razor source. Since the original string is
|
||||
// an attribute value that may have been quoted with single quotes, must handle any double quotes
|
||||
// in the value. Writing the value out surrounded by double quotes.
|
||||
var stringValue = stringWriter.ToString().Replace("\"", """);
|
||||
writer.Write(stringValue);
|
||||
stringValue = stringWriter.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// In this case the text likely came directly from the Razor source. Since the original string is
|
||||
// an attribute value that may have been quoted with single quotes, must handle any double quotes
|
||||
// in the value. Writing the value out surrounded by double quotes.
|
||||
content.AppendHtml(stringValue.Replace("\"", """));
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@
|
|||
doc.write('<link rel="stylesheet" href="' + fallbackHref[i] + '"/>');
|
||||
}
|
||||
}
|
||||
})("[[[0]]]", "[[[1]]]", [[[2]]]);
|
||||
})();
|
||||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="IHtmlContent"/> instance containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
public static Task<IHtmlContent> PartialAsync(
|
||||
|
|
@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// </param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="IHtmlContent"/> instance containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
public static Task<IHtmlContent> PartialAsync(
|
||||
|
|
@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// </param>
|
||||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="IHtmlContent"/> instance containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
public static Task<IHtmlContent> PartialAsync(
|
||||
|
|
@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Returns a new <see cref="HtmlString"/> containing the created HTML.
|
||||
/// Returns a new <see cref="IHtmlContent"/> instance containing the created HTML.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method synchronously calls and blocks on
|
||||
|
|
@ -141,7 +141,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// </param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
/// Returns a new <see cref="HtmlString"/> containing the created HTML.
|
||||
/// Returns a new <see cref="IHtmlContent"/> instance containing the created HTML.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method synchronously calls and blocks on
|
||||
|
|
@ -174,7 +174,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// </param>
|
||||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
/// Returns a new <see cref="HtmlString"/> containing the created HTML.
|
||||
/// Returns a new <see cref="IHtmlContent"/> instance containing the created HTML.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method synchronously calls and blocks on
|
||||
|
|
@ -208,7 +208,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
/// Returns a new <see cref="HtmlString"/> containing the created HTML.
|
||||
/// Returns a new <see cref="IHtmlContent"/> instance containing the created HTML.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method synchronously calls and blocks on
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// A <see cref="Task"/> that on completion returns a new <see cref="IHtmlContent"/> instance containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
Task<IHtmlContent> PartialAsync(string partialViewName, object model, ViewDataDictionary viewData);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using System.Text;
|
|||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
|
|
@ -252,6 +251,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||
{
|
||||
var htmlTextWriter = writer as HtmlTextWriter;
|
||||
if (htmlTextWriter != null)
|
||||
{
|
||||
// As a perf optimization, we can buffer this output rather than writing it
|
||||
// out character by character.
|
||||
htmlTextWriter.Write(this);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TagRenderMode)
|
||||
{
|
||||
case TagRenderMode.StartTag:
|
||||
|
|
|
|||
|
|
@ -866,18 +866,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
if (tagBuilder != null)
|
||||
{
|
||||
tagBuilder.TagRenderMode = TagRenderMode.StartTag;
|
||||
|
||||
// As a perf optimization, we can buffer this output rather than writing it
|
||||
// out character by character.
|
||||
var htmlWriter = ViewContext.Writer as HtmlTextWriter;
|
||||
if (htmlWriter == null)
|
||||
{
|
||||
tagBuilder.WriteTo(ViewContext.Writer, _htmlEncoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
htmlWriter.Write(tagBuilder);
|
||||
}
|
||||
tagBuilder.WriteTo(ViewContext.Writer, _htmlEncoder);
|
||||
}
|
||||
|
||||
return CreateForm();
|
||||
|
|
@ -920,18 +909,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
if (tagBuilder != null)
|
||||
{
|
||||
tagBuilder.TagRenderMode = TagRenderMode.StartTag;
|
||||
|
||||
// As a perf optimization, we can buffer this output rather than writing it
|
||||
// out character by character.
|
||||
var htmlWriter = ViewContext.Writer as HtmlTextWriter;
|
||||
if (htmlWriter == null)
|
||||
{
|
||||
tagBuilder.WriteTo(ViewContext.Writer, _htmlEncoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
htmlWriter.Write(tagBuilder);
|
||||
}
|
||||
tagBuilder.WriteTo(ViewContext.Writer, _htmlEncoder);
|
||||
}
|
||||
|
||||
return CreateForm();
|
||||
|
|
|
|||
|
|
@ -39,7 +39,17 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
throw new ArgumentNullException(nameof(encoder));
|
||||
}
|
||||
|
||||
encoder.Encode(writer, _input);
|
||||
var htmlTextWriter = writer as HtmlTextWriter;
|
||||
if (htmlTextWriter != null)
|
||||
{
|
||||
// As a perf optimization, we can buffer this output rather than writing it
|
||||
// out character by character.
|
||||
htmlTextWriter.Write(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Encode(writer, _input);
|
||||
}
|
||||
}
|
||||
|
||||
private string DebuggerToString()
|
||||
|
|
|
|||
|
|
@ -961,13 +961,14 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
// Assert
|
||||
var htmlAttribute = Assert.Single(executionContext.HTMLAttributes);
|
||||
Assert.Equal("someattr", htmlAttribute.Name, StringComparer.Ordinal);
|
||||
Assert.IsType<HtmlString>(htmlAttribute.Value);
|
||||
Assert.Equal(expectedValue, HtmlContentUtilities.HtmlContentToString((IHtmlContent)htmlAttribute.Value));
|
||||
var htmlContent = Assert.IsAssignableFrom<IHtmlContent>(htmlAttribute.Value);
|
||||
Assert.Equal(expectedValue, HtmlContentUtilities.HtmlContentToString(htmlContent), StringComparer.Ordinal);
|
||||
Assert.False(htmlAttribute.Minimized);
|
||||
|
||||
var allAttribute = Assert.Single(executionContext.AllAttributes);
|
||||
Assert.Equal("someattr", allAttribute.Name, StringComparer.Ordinal);
|
||||
Assert.IsType<HtmlString>(allAttribute.Value);
|
||||
Assert.Equal(expectedValue, allAttribute.Value.ToString(), StringComparer.Ordinal);
|
||||
htmlContent = Assert.IsAssignableFrom<IHtmlContent>(allAttribute.Value);
|
||||
Assert.Equal(expectedValue, HtmlContentUtilities.HtmlContentToString(htmlContent), StringComparer.Ordinal);
|
||||
Assert.False(allAttribute.Minimized);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Mvc.TestCommon;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
|
|
@ -22,22 +24,13 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
get
|
||||
{
|
||||
// url, expectedHref
|
||||
return new TheoryData<object, object>
|
||||
return new TheoryData<string, string>
|
||||
{
|
||||
{ "~/home/index.html", "/approot/home/index.html" },
|
||||
{ " ~/home/index.html", "/approot/home/index.html" },
|
||||
{ new HtmlString("~/home/index.html"), new HtmlString("HtmlEncode[[/approot/]]home/index.html") },
|
||||
{
|
||||
new HtmlString(" ~/home/index.html"),
|
||||
new HtmlString("HtmlEncode[[/approot/]]home/index.html")
|
||||
},
|
||||
{
|
||||
"~/home/index.html ~/secondValue/index.html",
|
||||
"/approot/home/index.html ~/secondValue/index.html"
|
||||
},
|
||||
{
|
||||
new HtmlString("~/home/index.html ~/secondValue/index.html"),
|
||||
new HtmlString("HtmlEncode[[/approot/]]home/index.html ~/secondValue/index.html")
|
||||
"~/home/index.html ~/secondValue/index.html",
|
||||
"/approot/home/index.html ~/secondValue/index.html"
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -45,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
|
||||
[Theory]
|
||||
[MemberData(nameof(ResolvableUrlData))]
|
||||
public void Process_ResolvesTildeSlashValues(object url, object expectedHref)
|
||||
public void Process_ResolvesTildeSlashValues(string url, string expectedHref)
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperOutput = new TagHelperOutput(
|
||||
|
|
@ -77,8 +70,64 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
// Assert
|
||||
var attribute = Assert.Single(tagHelperOutput.Attributes);
|
||||
Assert.Equal("href", attribute.Name, StringComparer.Ordinal);
|
||||
Assert.IsType(expectedHref.GetType(), url);
|
||||
Assert.Equal(expectedHref.ToString(), attribute.Value.ToString());
|
||||
var attributeValue = Assert.IsType<string>(attribute.Value);
|
||||
Assert.Equal(expectedHref, attributeValue, StringComparer.Ordinal);
|
||||
Assert.False(attribute.Minimized);
|
||||
}
|
||||
|
||||
public static TheoryData ResolvableUrlHtmlStringData
|
||||
{
|
||||
get
|
||||
{
|
||||
// url, expectedHref
|
||||
return new TheoryData<HtmlString, string>
|
||||
{
|
||||
{ new HtmlString("~/home/index.html"), "HtmlEncode[[/approot/]]home/index.html" },
|
||||
{ new HtmlString(" ~/home/index.html"), "HtmlEncode[[/approot/]]home/index.html" },
|
||||
{
|
||||
new HtmlString("~/home/index.html ~/secondValue/index.html"),
|
||||
"HtmlEncode[[/approot/]]home/index.html ~/secondValue/index.html"
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ResolvableUrlHtmlStringData))]
|
||||
public void Process_ResolvesTildeSlashValues_InHtmlString(object url, string expectedHref)
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperOutput = new TagHelperOutput(
|
||||
tagName: "a",
|
||||
attributes: new TagHelperAttributeList
|
||||
{
|
||||
{ "href", url }
|
||||
},
|
||||
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
|
||||
var urlHelperMock = new Mock<IUrlHelper>();
|
||||
urlHelperMock
|
||||
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
|
||||
.Returns(new Func<string, string>(value => "/approot" + value.Substring(1)));
|
||||
var urlHelperFactory = new Mock<IUrlHelperFactory>();
|
||||
urlHelperFactory
|
||||
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
|
||||
.Returns(urlHelperMock.Object);
|
||||
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, new HtmlTestEncoder());
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
|
||||
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: "test");
|
||||
|
||||
// Act
|
||||
tagHelper.Process(context, tagHelperOutput);
|
||||
|
||||
// Assert
|
||||
var attribute = Assert.Single(tagHelperOutput.Attributes);
|
||||
Assert.Equal("href", attribute.Name, StringComparer.Ordinal);
|
||||
var htmlContent = Assert.IsAssignableFrom<IHtmlContent>(attribute.Value);
|
||||
Assert.Equal(expectedHref, HtmlContentUtilities.HtmlContentToString(htmlContent), StringComparer.Ordinal);
|
||||
Assert.False(attribute.Minimized);
|
||||
}
|
||||
|
||||
|
|
@ -87,25 +136,20 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
get
|
||||
{
|
||||
// url
|
||||
return new TheoryData<object>
|
||||
return new TheoryData<string>
|
||||
{
|
||||
{ "/home/index.html" },
|
||||
{ "~ /home/index.html" },
|
||||
{ "/home/index.html ~/second/wontresolve.html" },
|
||||
{ " ~\\home\\index.html" },
|
||||
{ "~\\/home/index.html" },
|
||||
{ new HtmlString("/home/index.html") },
|
||||
{ new HtmlString("~ /home/index.html") },
|
||||
{ new HtmlString("/home/index.html ~/second/wontresolve.html") },
|
||||
{ new HtmlString("~\\home\\index.html") },
|
||||
{ new HtmlString("~\\/home/index.html") },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(UnresolvableUrlData))]
|
||||
public void Process_DoesNotResolveNonTildeSlashValues(object url)
|
||||
public void Process_DoesNotResolveNonTildeSlashValues(string url)
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperOutput = new TagHelperOutput(
|
||||
|
|
@ -123,7 +167,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
urlHelperFactory
|
||||
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
|
||||
.Returns(urlHelperMock.Object);
|
||||
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, htmlEncoder: null);
|
||||
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, new HtmlTestEncoder());
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
|
||||
|
|
@ -137,7 +181,63 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
// Assert
|
||||
var attribute = Assert.Single(tagHelperOutput.Attributes);
|
||||
Assert.Equal("href", attribute.Name, StringComparer.Ordinal);
|
||||
Assert.Equal(url, attribute.Value);
|
||||
var attributeValue = Assert.IsType<string>(attribute.Value);
|
||||
Assert.Equal(url, attributeValue, StringComparer.Ordinal);
|
||||
Assert.False(attribute.Minimized);
|
||||
}
|
||||
|
||||
public static TheoryData UnresolvableUrlHtmlStringData
|
||||
{
|
||||
get
|
||||
{
|
||||
// url
|
||||
return new TheoryData<HtmlString>
|
||||
{
|
||||
{ new HtmlString("/home/index.html") },
|
||||
{ new HtmlString("~ /home/index.html") },
|
||||
{ new HtmlString("/home/index.html ~/second/wontresolve.html") },
|
||||
{ new HtmlString("~\\home\\index.html") },
|
||||
{ new HtmlString("~\\/home/index.html") },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(UnresolvableUrlHtmlStringData))]
|
||||
public void Process_DoesNotResolveNonTildeSlashValues_InHtmlString(HtmlString url)
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperOutput = new TagHelperOutput(
|
||||
tagName: "a",
|
||||
attributes: new TagHelperAttributeList
|
||||
{
|
||||
{ "href", url }
|
||||
},
|
||||
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
|
||||
var urlHelperMock = new Mock<IUrlHelper>();
|
||||
urlHelperMock
|
||||
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
|
||||
.Returns("approot/home/index.html");
|
||||
var urlHelperFactory = new Mock<IUrlHelperFactory>();
|
||||
urlHelperFactory
|
||||
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
|
||||
.Returns(urlHelperMock.Object);
|
||||
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, new HtmlTestEncoder());
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
|
||||
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: "test");
|
||||
|
||||
// Act
|
||||
tagHelper.Process(context, tagHelperOutput);
|
||||
|
||||
// Assert
|
||||
var attribute = Assert.Single(tagHelperOutput.Attributes);
|
||||
Assert.Equal("href", attribute.Name, StringComparer.Ordinal);
|
||||
var attributeValue = Assert.IsType<HtmlString>(attribute.Value);
|
||||
Assert.Equal(url.ToString(), attributeValue.ToString(), StringComparer.Ordinal);
|
||||
Assert.False(attribute.Minimized);
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +297,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
|
|||
urlHelperFactory
|
||||
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
|
||||
.Returns(urlHelperMock.Object);
|
||||
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, htmlEncoder: null);
|
||||
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, new HtmlTestEncoder());
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
{
|
||||
// Arrange
|
||||
var resource = "window.alert('An alert');";
|
||||
var expected = resource.Substring(0, resource.Length - 2);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(resource));
|
||||
var getManifestResourceStream = new Func<string, Stream>(name => stream);
|
||||
var cache = new ConcurrentDictionary<string, string>();
|
||||
|
|
@ -24,7 +25,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
var result = JavaScriptResources.GetEmbeddedJavaScript("test.js", getManifestResourceStream, cache);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(resource, result);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -32,6 +33,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
{
|
||||
// Arrange
|
||||
var resource = "window.alert('An alert');";
|
||||
var expected = resource.Substring(0, resource.Length - 2);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(resource));
|
||||
var getManifestResourceStream = new Func<string, Stream>(name => stream);
|
||||
var cache = new ConcurrentDictionary<string, string>();
|
||||
|
|
@ -43,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
Assert.Collection(cache, kvp =>
|
||||
{
|
||||
Assert.Equal("test.js", kvp.Key);
|
||||
Assert.Equal(resource, kvp.Value);
|
||||
Assert.Equal(expected, kvp.Value);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -70,12 +72,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("window.alert(\"[[[0]]]\")", "window.alert(\"{0}\")")]
|
||||
[InlineData("var test = { a: 1 };", "var test = {{ a: 1 }};")]
|
||||
[InlineData("var test = { a: 1, b: \"[[[0]]]\" };", "var test = {{ a: 1, b: \"{0}\" }};")]
|
||||
public void GetEmbeddedJavaScript_PreparesJavaScriptCorrectly(string resource, string expectedResult)
|
||||
[InlineData("window.alert(\"[[[0]]]\")")]
|
||||
[InlineData("var test = { a: 1 };")]
|
||||
[InlineData("var test = { a: 1, b: \"[[[0]]]\" };")]
|
||||
public void GetEmbeddedJavaScript_PreparesJavaScriptCorrectly(string resource)
|
||||
{
|
||||
// Arrange
|
||||
var expected = resource.Substring(0, resource.Length - 2);
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(resource));
|
||||
var getManifestResourceStream = new Func<string, Stream>(name => stream);
|
||||
var cache = new ConcurrentDictionary<string, string>();
|
||||
|
|
@ -84,7 +87,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
var result = JavaScriptResources.GetEmbeddedJavaScript("test.js", getManifestResourceStream, cache);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue