Add `null` checks for MVC tag helpers

This commit is contained in:
Doug Bunting 2015-10-14 11:27:25 -07:00
parent c3ac457c20
commit 9aed5efd51
20 changed files with 276 additions and 27 deletions

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Extensions.WebEncoders;
@ -108,6 +107,16 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
IEnumerable<string> attributeNames;
if (ElementAttributeLookups.TryGetValue(output.TagName, out attributeNames))
{
@ -130,6 +139,16 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
/// <param name="output">The <see cref="TagHelperOutput"/>.</param>
protected void ProcessUrlAttribute(string attributeName, TagHelperOutput output)
{
if (attributeName == null)
{
throw new ArgumentNullException(nameof(attributeName));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
IEnumerable<TagHelperAttribute> attributes;
if (output.Attributes.TryGetAttributes(attributeName, out attributes))
{

View File

@ -111,6 +111,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// </exception>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// If "href" is already set, it means the user is attempting to use a normal anchor.
if (output.Attributes.ContainsName(Href))
{

View File

@ -138,6 +138,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <inheritdoc />
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
TagHelperContent result = null;
if (Enabled)
{

View File

@ -48,6 +48,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// Always strip the outer tag name as we never want <environment> to render
output.TagName = null;
@ -80,7 +90,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// Matching environment name found, do nothing
return;
}
// No matching environment name found, suppress all output
output.SuppressOutput();
}

View File

@ -99,6 +99,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// </exception>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var antiforgeryDefault = true;
// If "action" is already set, it means the user is attempting to use a normal <form>.

View File

@ -1,10 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor.TagHelpers;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@ -87,6 +87,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
output.CopyHtmlAttribute(SrcAttributeName, context);
ProcessUrlAttribute(SrcAttributeName, output);

View File

@ -133,6 +133,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// </exception>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying
// from a TagBuilder.
if (InputTypeName != null)

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures;
@ -50,6 +51,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var tagBuilder = Generator.GenerateLabel(
ViewContext,
For.ModelExplorer,

View File

@ -8,7 +8,6 @@ using System.Linq;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor.TagHelpers;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@ -217,7 +216,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
{
string resolvedUrl;
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// Pass through attribute that is also a well-known HTML attribute.
if (Href != null)
@ -274,6 +281,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
if (mode == Mode.Fallback)
{
string resolvedUrl;
if (TryResolveUrl(FallbackHref, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
{
FallbackHref = resolvedUrl;

View File

@ -61,6 +61,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// </remarks>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// Pass through attributes that are also well-known HTML attributes.
if (Value != null)
{

View File

@ -7,7 +7,6 @@ using System.Linq;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor.TagHelpers;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@ -185,7 +184,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
{
string resolvedUrl;
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// Pass through attribute that is also a well-known HTML attribute.
if (Src != null)
@ -242,6 +249,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
if (mode == Mode.Fallback)
{
string resolvedUrl;
if (TryResolveUrl(FallbackSrc, encodeWebRoot: false, resolvedUrl: out resolvedUrl))
{
FallbackSrc = resolvedUrl;

View File

@ -76,6 +76,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// </exception>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient.
// IHtmlGenerator will enforce name requirements.
var metadata = For.Metadata;

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@ -49,6 +50,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var tagBuilder = Generator.GenerateTextArea(
ViewContext,
For.ModelExplorer,

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures;
@ -51,6 +52,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
if (For != null)
{
var tagBuilder = Generator.GenerateValidationMessage(ViewContext,

View File

@ -83,6 +83,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <remarks>Does nothing if <see cref="ValidationSummary"/> is <see cref="ValidationSummary.None"/>.</remarks>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
if (ValidationSummary == ValidationSummary.None)
{
return;

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.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Extensions.WebEncoders;
using Moq;
@ -57,8 +59,15 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
.Returns(new Func<string, string>(value => "/approot" + value.Substring(1)));
var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, new TestHtmlEncoder());
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act
tagHelper.Process(context: null, output: tagHelperOutput);
tagHelper.Process(context, tagHelperOutput);
// Assert
var attribute = Assert.Single(tagHelperOutput.Attributes);
@ -106,8 +115,15 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
.Returns("approot/home/index.html");
var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, htmlEncoder: null);
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act
tagHelper.Process(context: null, output: tagHelperOutput);
tagHelper.Process(context, tagHelperOutput);
// Assert
var attribute = Assert.Single(tagHelperOutput.Attributes);
@ -128,8 +144,15 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
});
var tagHelper = new UrlResolutionTagHelper(urlHelper: null, htmlEncoder: null);
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act
tagHelper.Process(context: null, output: tagHelperOutput);
tagHelper.Process(context, tagHelperOutput);
// Assert
var attribute = Assert.Single(tagHelperOutput.Attributes);
@ -162,9 +185,16 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
.Returns("UnexpectedResult");
var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, htmlEncoder: null);
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
() => tagHelper.Process(context: null, output: tagHelperOutput));
() => tagHelper.Process(context, tagHelperOutput));
Assert.Equal(expectedExceptionMessage, exception.Message, StringComparer.Ordinal);
}
}

View File

@ -10,7 +10,6 @@ using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Extensions.WebEncoders.Testing;
using Moq;
using Xunit;
@ -220,9 +219,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"'asp-action', 'asp-controller', 'asp-route', 'asp-protocol', 'asp-host', or " +
"'asp-fragment' attribute.";
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => anchorTagHelper.ProcessAsync(context: null, output: output));
() => anchorTagHelper.ProcessAsync(context, output));
Assert.Equal(expectedErrorMessage, ex.Message);
}
@ -248,9 +254,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedErrorMessage = "Cannot determine an 'href' attribute for <a>. An <a> with a specified " +
"'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => anchorTagHelper.ProcessAsync(context: null, output: output));
() => anchorTagHelper.ProcessAsync(context, output));
Assert.Equal(expectedErrorMessage, ex.Message);
}

View File

@ -407,9 +407,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
"'action' must not have attributes starting with 'asp-route-' or an " +
"'asp-action' or 'asp-controller' or 'asp-route' attribute.";
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => formTagHelper.ProcessAsync(context: null, output: tagHelperOutput));
() => formTagHelper.ProcessAsync(context, tagHelperOutput));
Assert.Equal(expectedErrorMessage, ex.Message);
}
@ -431,9 +438,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " +
"'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => formTagHelper.ProcessAsync(context: null, output: output));
() => formTagHelper.ProcessAsync(context, output));
Assert.Equal(expectedErrorMessage, ex.Message);
}

View File

@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent);
var viewContext = TestableHtmlGenerator.GetViewContext(model: null,
htmlGenerator: htmlGenerator,
metadataProvider: metadataProvider);
@ -127,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
validationMessageTagHelper.ViewContext = expectedViewContext;
// Act & Assert
await validationMessageTagHelper.ProcessAsync(context, output: output);
await validationMessageTagHelper.ProcessAsync(context, output);
generator.Verify();
Assert.Equal("span", output.TagName);
@ -185,7 +185,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
validationMessageTagHelper.ViewContext = viewContext;
// Act
await validationMessageTagHelper.ProcessAsync(context, output: output);
await validationMessageTagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal("span", output.TagName);
@ -243,7 +243,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
validationMessageTagHelper.ViewContext = viewContext;
// Act
await validationMessageTagHelper.ProcessAsync(context, output: output);
await validationMessageTagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal("span", output.TagName);
@ -271,11 +271,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent);
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
var viewContext = CreateViewContext();
validationMessageTagHelper.ViewContext = viewContext;
// Act
await validationMessageTagHelper.ProcessAsync(context: null, output: output);
await validationMessageTagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal("span", output.TagName);

View File

@ -115,11 +115,17 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent);
validationSummaryTagHelper.ViewContext = expectedViewContext;
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act & Assert
await validationSummaryTagHelper.ProcessAsync(context: null, output: output);
await validationSummaryTagHelper.ProcessAsync(context, output);
generator.Verify();
Assert.Equal("div", output.TagName);
@ -166,8 +172,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var viewContext = CreateViewContext();
validationSummaryTagHelper.ViewContext = viewContext;
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act
await validationSummaryTagHelper.ProcessAsync(context: null, output: output);
await validationSummaryTagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal("div", output.TagName);
@ -207,8 +220,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var viewContext = CreateViewContext();
validationSummaryTagHelper.ViewContext = viewContext;
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act
await validationSummaryTagHelper.ProcessAsync(context: null, output: output);
await validationSummaryTagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal("div", output.TagName);
@ -255,8 +275,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var viewContext = CreateViewContext();
validationSummaryTagHelper.ViewContext = viewContext;
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
items: new Dictionary<object, object>(),
uniqueId: "test",
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
// Act
await validationSummaryTagHelper.ProcessAsync(context: null, output: output);
await validationSummaryTagHelper.ProcessAsync(context, output);
// Assert
Assert.Equal("div", output.TagName);