diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/HtmlHelperFormExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/HtmlHelperFormExtensions.cs index 1376282a38..34d85ff34d 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/HtmlHelperFormExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/HtmlHelperFormExtensions.cs @@ -6,7 +6,7 @@ using System; namespace Microsoft.AspNet.Mvc.Rendering { /// - /// DisplayName-related extensions for . + /// Form-related extensions for . /// public static class HtmlHelperFormExtensions { @@ -29,8 +29,45 @@ namespace Microsoft.AspNet.Mvc.Rendering } // Generates
. - return htmlHelper.BeginForm(actionName: null, controllerName: null, routeValues: null, - method: FormMethod.Post, htmlAttributes: null); + return htmlHelper.BeginForm( + actionName: null, + controllerName: null, + routeValues: null, + method: FormMethod.Post, + suppressAntiforgery: false, + htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. The <form>'s action attribute value will + /// match the current request. + /// + /// The instance this method extends. + /// + /// If true, suppresses the generation an <input> of type "hidden" with an antiforgery token. By + /// default <form> elements will automatically include an antiforgery token. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginForm(this IHtmlHelper htmlHelper, bool suppressAntiforgery) + { + if (htmlHelper == null) + { + throw new ArgumentNullException(nameof(htmlHelper)); + } + + // Generates . + return htmlHelper.BeginForm( + actionName: null, + controllerName: null, + routeValues: null, + method: FormMethod.Post, + suppressAntiforgery: suppressAntiforgery, + htmlAttributes: null); } /// @@ -52,8 +89,13 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName: null, controllerName: null, routeValues: null, - method: method, htmlAttributes: null); + return htmlHelper.BeginForm( + actionName: null, + controllerName: null, + routeValues: null, + method: method, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -83,8 +125,54 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName: null, controllerName: null, routeValues: null, - method: method, htmlAttributes: htmlAttributes); + return htmlHelper.BeginForm( + actionName: null, + controllerName: null, + routeValues: null, + method: method, + suppressAntiforgery: false, + htmlAttributes: htmlAttributes); + } + + /// + /// Renders a <form> start tag to the response. When the user submits the form, the + /// current action will process the request. + /// + /// The instance this method extends. + /// The HTTP method for processing the form, either GET or POST. + /// + /// If true, suppresses the generation an <input> of type "hidden" with an antiforgery token. By + /// default <form> elements will automatically include an antiforgery token. + /// + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML + /// attributes. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginForm( + this IHtmlHelper htmlHelper, + FormMethod method, + bool suppressAntiforgery, + object htmlAttributes) + { + if (htmlHelper == null) + { + throw new ArgumentNullException(nameof(htmlHelper)); + } + + return htmlHelper.BeginForm( + actionName: null, + controllerName: null, + routeValues: null, + method: method, + suppressAntiforgery: suppressAntiforgery, + htmlAttributes: htmlAttributes); } /// @@ -112,8 +200,13 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName: null, controllerName: null, routeValues: routeValues, - method: FormMethod.Post, htmlAttributes: null); + return htmlHelper.BeginForm( + actionName: null, + controllerName: null, + routeValues: routeValues, + method: FormMethod.Post, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -139,8 +232,13 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName, controllerName, routeValues: null, - method: FormMethod.Post, htmlAttributes: null); + return htmlHelper.BeginForm( + actionName, + controllerName, + routeValues: null, + method: FormMethod.Post, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -174,8 +272,13 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName, controllerName, routeValues, - FormMethod.Post, htmlAttributes: null); + return htmlHelper.BeginForm( + actionName, + controllerName, + routeValues, + FormMethod.Post, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -203,8 +306,13 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName, controllerName, routeValues: null, - method: method, htmlAttributes: null); + return htmlHelper.BeginForm( + actionName, + controllerName, + routeValues: null, + method: method, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -240,8 +348,13 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName, controllerName, routeValues, - method, htmlAttributes: null); + return htmlHelper.BeginForm( + actionName, + controllerName, + routeValues, + method, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -275,8 +388,13 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginForm(actionName, controllerName, routeValues: null, - method: method, htmlAttributes: htmlAttributes); + return htmlHelper.BeginForm( + actionName, + controllerName, + routeValues: null, + method: method, + suppressAntiforgery: false, + htmlAttributes: htmlAttributes); } /// @@ -308,6 +426,44 @@ namespace Microsoft.AspNet.Mvc.Rendering routeName: null, routeValues: routeValues, method: FormMethod.Post, + suppressAntiforgery: false, + htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. The first route that can provide a URL with the + /// specified generates the <form>'s action attribute value. + /// + /// The instance this method extends. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route + /// parameters. + /// + /// + /// If true, suppresses the generation an <input> of type "hidden" with an antiforgery token. By + /// default <form> elements will automatically include an antiforgery token. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm(this IHtmlHelper htmlHelper, object routeValues, bool suppressAntiforgery) + { + if (htmlHelper == null) + { + throw new ArgumentNullException(nameof(htmlHelper)); + } + + return htmlHelper.BeginRouteForm( + routeName: null, + routeValues: routeValues, + method: FormMethod.Post, + suppressAntiforgery: suppressAntiforgery, htmlAttributes: null); } @@ -334,6 +490,38 @@ namespace Microsoft.AspNet.Mvc.Rendering routeName, routeValues: null, method: FormMethod.Post, + suppressAntiforgery: false, + htmlAttributes: null); + } + + /// + /// Renders a <form> start tag to the response. The route with name + /// generates the <form>'s action attribute value. + /// + /// The instance this method extends. + /// The name of the route. + /// + /// If true, suppresses the generation an <input> of type "hidden" with an antiforgery token. By + /// default <form> elements will automatically include an antiforgery token. + /// + /// + /// An instance which renders the </form> end tag when disposed. + /// + /// + /// In this context, "renders" means the method writes its output using . + /// + public static MvcForm BeginRouteForm(this IHtmlHelper htmlHelper, string routeName, bool suppressAntiforgery) + { + if (htmlHelper == null) + { + throw new ArgumentNullException(nameof(htmlHelper)); + } + + return htmlHelper.BeginRouteForm( + routeName, + routeValues: null, + method: FormMethod.Post, + suppressAntiforgery: suppressAntiforgery, htmlAttributes: null); } @@ -366,7 +554,12 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginRouteForm(routeName, routeValues, FormMethod.Post, htmlAttributes: null); + return htmlHelper.BeginRouteForm( + routeName, + routeValues, + FormMethod.Post, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -392,7 +585,12 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginRouteForm(routeName, routeValues: null, method: method, htmlAttributes: null); + return htmlHelper.BeginRouteForm( + routeName, + routeValues: null, + method: method, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -426,7 +624,12 @@ namespace Microsoft.AspNet.Mvc.Rendering throw new ArgumentNullException(nameof(htmlHelper)); } - return htmlHelper.BeginRouteForm(routeName, routeValues, method, htmlAttributes: null); + return htmlHelper.BeginRouteForm( + routeName, + routeValues, + method, + suppressAntiforgery: false, + htmlAttributes: null); } /// @@ -462,6 +665,7 @@ namespace Microsoft.AspNet.Mvc.Rendering routeName, routeValues: null, method: method, + suppressAntiforgery: false, htmlAttributes: htmlAttributes); } } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/IHtmlHelper.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/IHtmlHelper.cs index a274501b04..babb080eaa 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/IHtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Rendering/IHtmlHelper.cs @@ -114,6 +114,10 @@ namespace Microsoft.AspNet.Mvc.Rendering /// instance containing the route parameters. /// /// The HTTP method for processing the form, either GET or POST. + /// + /// If true, suppresses the generation an <input> of type "hidden" with an antiforgery token. By + /// default <form> elements will automatically include an antiforgery token. + /// /// /// An that contains the HTML attributes for the element. Alternatively, an /// instance containing the HTML attributes. @@ -129,6 +133,7 @@ namespace Microsoft.AspNet.Mvc.Rendering string controllerName, object routeValues, FormMethod method, + bool suppressAntiforgery, object htmlAttributes); /// @@ -143,6 +148,9 @@ namespace Microsoft.AspNet.Mvc.Rendering /// instance containing the route parameters. /// /// The HTTP method for processing the form, either GET or POST. + /// + /// Determines whether or not to include an <input> of type "hidden" with an antiforgery token. + /// /// /// An that contains the HTML attributes for the element. Alternatively, an /// instance containing the HTML attributes. @@ -157,6 +165,7 @@ namespace Microsoft.AspNet.Mvc.Rendering string routeName, object routeValues, FormMethod method, + bool suppressAntiforgery, object htmlAttributes); /// diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/FormContext.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/FormContext.cs index 4dfc738c41..b54fcd156d 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/FormContext.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/FormContext.cs @@ -31,6 +31,8 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures } } + public bool HasAntiforgeryToken { get; set; } + public bool HasFormData => _formData != null; public bool HasEndOfFormContent => _endOfFormContent != null; diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs index cc57851e91..1c490a3a44 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs @@ -270,6 +270,14 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// public IHtmlContent AntiForgeryToken() { + // If we're inside a BeginForm/BeginRouteForm, the antiforgery token might have already been + // created and appended to the 'end form' content. + if (ViewContext.FormContext.HasAntiforgeryToken) + { + return HtmlString.Empty; + } + + ViewContext.FormContext.HasAntiforgeryToken = true; var html = _htmlGenerator.GenerateAntiforgery(ViewContext); return html ?? HtmlString.Empty; } @@ -280,6 +288,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures string controllerName, object routeValues, FormMethod method, + bool suppressAntiforgery, object htmlAttributes) { // Push the new FormContext; MvcForm.GenerateEndForm() does the corresponding pop. @@ -288,11 +297,16 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures CanRenderAtEndOfForm = true }; - return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributes); + return GenerateForm(actionName, controllerName, routeValues, method, suppressAntiforgery, htmlAttributes); } /// - public MvcForm BeginRouteForm(string routeName, object routeValues, FormMethod method, object htmlAttributes) + public MvcForm BeginRouteForm( + string routeName, + object routeValues, + FormMethod method, + bool suppressAntiforgery, + object htmlAttributes) { // Push the new FormContext; MvcForm.GenerateEndForm() does the corresponding pop. _viewContext.FormContext = new FormContext @@ -300,7 +314,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures CanRenderAtEndOfForm = true }; - return GenerateRouteForm(routeName, routeValues, method, htmlAttributes); + return GenerateRouteForm(routeName, routeValues, method, suppressAntiforgery, htmlAttributes); } /// @@ -852,6 +866,10 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// instance containing the route parameters. /// /// The HTTP method for processing the form, either GET or POST. + /// + /// If true, suppresses the generation an <input> of type "hidden" with an antiforgery token. By + /// default <form> elements will automatically include an antiforgery token. + /// /// /// An that contains the HTML attributes for the element. Alternatively, an /// instance containing the HTML attributes. @@ -867,6 +885,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures string controllerName, object routeValues, FormMethod method, + bool suppressAntiforgery, object htmlAttributes) { var tagBuilder = _htmlGenerator.GenerateForm( @@ -882,6 +901,12 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures tagBuilder.WriteTo(ViewContext.Writer, _htmlEncoder); } + if (!suppressAntiforgery) + { + ViewContext.FormContext.EndOfFormContent.Add(_htmlGenerator.GenerateAntiforgery(ViewContext)); + ViewContext.FormContext.HasAntiforgeryToken = true; + } + return CreateForm(); } @@ -897,6 +922,10 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// instance containing the route parameters. /// /// The HTTP method for processing the form, either GET or POST. + /// + /// If true, suppresses the generation an <input> of type "hidden" with an antiforgery token. By + /// default <form> elements will automatically include an antiforgery token. + /// /// /// An that contains the HTML attributes for the element. Alternatively, an /// instance containing the HTML attributes. @@ -911,6 +940,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures string routeName, object routeValues, FormMethod method, + bool suppressAntiforgery, object htmlAttributes) { var tagBuilder = _htmlGenerator.GenerateRouteForm( @@ -925,6 +955,12 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures tagBuilder.WriteTo(ViewContext.Writer, _htmlEncoder); } + if (!suppressAntiforgery) + { + ViewContext.FormContext.EndOfFormContent.Add(_htmlGenerator.GenerateAntiforgery(ViewContext)); + ViewContext.FormContext.HasAntiforgeryToken = true; + } + return CreateForm(); } diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlGenerationTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlGenerationTest.cs index 1e53fed94e..ea1fe99f3c 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlGenerationTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/HtmlGenerationTest.cs @@ -44,12 +44,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Testing attribute values with boolean and null values { "AttributesWithBooleanValues", null }, // Testing SelectTagHelper with Html.BeginForm - { "CreateWarehouse", null }, + { "CreateWarehouse", "/HtmlGeneration_Home/CreateWarehouse" }, // Testing the HTML helpers with FormTagHelper { "EditWarehouse", null }, { "Form", "/HtmlGeneration_Home/Form" }, // Testing MVC tag helpers invoked in the editor templates from HTML helpers - { "EmployeeList", null }, + { "EmployeeList", "/HtmlGeneration_Home/EmployeeList" }, // Testing the EnvironmentTagHelper { "Environment", null }, // Testing the ImageTagHelper @@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests { "Order", "/HtmlGeneration_Order/Submit" }, { "OrderUsingHtmlHelpers", "/HtmlGeneration_Order/Submit" }, // Testing InputTagHelpers invoked in the partial views - { "ProductList", null }, + { "ProductList", "/HtmlGeneration_Product" }, }; // One path hits aspnet/External#50 with Mono on Mac. diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.CreateWarehouse.html b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.CreateWarehouse.html index 9df160372c..aab845064b 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.CreateWarehouse.html +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.CreateWarehouse.html @@ -16,5 +16,5 @@
- + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.EmployeeList.html b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.EmployeeList.html index daacb9b15f..edc86e3450 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.EmployeeList.html +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.EmployeeList.html @@ -94,5 +94,5 @@ EmployeeName_2 - + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductList.html b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductList.html index beb60a138c..9ad0850e70 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductList.html +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductList.html @@ -55,5 +55,5 @@ - + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs index 42cb56b97b..508eae10d6 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormExtensionsTest.cs @@ -280,7 +280,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, null, // actionName null, // controllerName @@ -289,6 +289,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -305,6 +309,76 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlGenerator.Verify(); } + [Fact] + public void BeginForm_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues() + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateForm( + htmlHelper.ViewContext, + null, // actionName + null, // controllerName + null, // routeValues + "post", // method + null)) // htmlAttributes + .Returns(tagBuilder) + .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginForm(suppressAntiforgery: false); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("
", builder.ToString()); + htmlGenerator.Verify(); + } + + [Fact] + public void BeginForm_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues() + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateForm( + htmlHelper.ViewContext, + null, // actionName + null, // controllerName + null, // routeValues + "post", // method + null)) // htmlAttributes + .Returns(tagBuilder) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginForm(suppressAntiforgery: true); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + [Theory] [MemberData(nameof(MethodDataSet))] public void BeginFormWithMethodParameter_CallsHtmlGeneratorWithExpectedValues(FormMethod method) @@ -314,7 +388,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, null, // actionName null, // controllerName @@ -323,6 +397,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -350,7 +428,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, null, // actionName null, // controllerName @@ -359,6 +437,10 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlAttributes)) .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -375,6 +457,82 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlGenerator.Verify(); } + [Theory] + [MemberData(nameof(MethodAndHtmlAttributesDataSet))] + public void BeginFormWithMethodAndHtmlAttributesParameters_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues( + FormMethod method, + object htmlAttributes) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateForm( + htmlHelper.ViewContext, + null, // actionName + null, // controllerName + null, // routeValues + method.ToString().ToLowerInvariant(), + htmlAttributes)) + .Returns(tagBuilder) + .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginForm(method, suppressAntiforgery: false, htmlAttributes: htmlAttributes); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + + [Theory] + [MemberData(nameof(MethodAndHtmlAttributesDataSet))] + public void BeginFormWithMethodAndHtmlAttributesParameters_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues( + FormMethod method, + object htmlAttributes) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateForm( + htmlHelper.ViewContext, + null, // actionName + null, // controllerName + null, // routeValues + method.ToString().ToLowerInvariant(), + htmlAttributes)) + .Returns(tagBuilder) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginForm(method, suppressAntiforgery: true, htmlAttributes: htmlAttributes); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + [Theory] [MemberData(nameof(RouteValuesDataSet))] public void BeginFormWithRouteValuesParameter_CallsHtmlGeneratorWithExpectedValues(object routeValues) @@ -384,7 +542,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, null, // actionName null, // controllerName @@ -393,6 +551,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -420,7 +582,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, actionName, controllerName, @@ -429,6 +591,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -457,7 +623,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, actionName, controllerName, @@ -466,6 +632,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -494,7 +664,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, actionName, controllerName, @@ -503,6 +673,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -532,7 +706,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, actionName, controllerName, @@ -541,6 +715,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -570,7 +748,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateForm( + .Setup(g => g.GenerateForm( htmlHelper.ViewContext, actionName, controllerName, @@ -579,6 +757,10 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlAttributes)) .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -595,6 +777,98 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlGenerator.Verify(); } + [Theory] + [MemberData(nameof(ActionNameControllerNameMethodAndHtmlAttributesDataSet))] + public void BeginFormWithActionNameContollerNameMethodAndHtmlAttributesParameters_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues( + string actionName, + string controllerName, + FormMethod method, + object htmlAttributes) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateForm( + htmlHelper.ViewContext, + actionName, + controllerName, + null, // routeValues + method.ToString().ToLowerInvariant(), + htmlAttributes)) + .Returns(tagBuilder) + .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginForm( + actionName, + controllerName, + routeValues: null, + method: method, + suppressAntiforgery: false, + htmlAttributes: htmlAttributes); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + + [Theory] + [MemberData(nameof(ActionNameControllerNameMethodAndHtmlAttributesDataSet))] + public void BeginFormWithActionNameContollerNameMethodAndHtmlAttributesParameters_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues( + string actionName, + string controllerName, + FormMethod method, + object htmlAttributes) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateForm( + htmlHelper.ViewContext, + actionName, + controllerName, + null, // routeValues + method.ToString().ToLowerInvariant(), + htmlAttributes)) + .Returns(tagBuilder) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginForm( + actionName, + controllerName, + routeValues: null, + method: method, + suppressAntiforgery: true, + htmlAttributes: htmlAttributes); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + [Theory] [MemberData(nameof(RouteValuesDataSet))] public void BeginRouteFormWithRouteValuesParameter_CallsHtmlGeneratorWithExpectedValues(object routeValues) @@ -604,7 +878,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateRouteForm( + .Setup(g => g.GenerateRouteForm( htmlHelper.ViewContext, null, // routeName routeValues, @@ -612,6 +886,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -628,6 +906,78 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlGenerator.Verify(); } + [Theory] + [MemberData(nameof(RouteValuesDataSet))] + public void BeginRouteFormWithRouteValuesParameter_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues( + object routeValues) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + htmlHelper.ViewContext, + null, // routeName + routeValues, + "post", // method + null)) // htmlAttributes + .Returns(tagBuilder) + .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginRouteForm(routeValues, suppressAntiforgery: false); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + + [Theory] + [MemberData(nameof(RouteValuesDataSet))] + public void BeginRouteFormWithRouteValuesParameter_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues( + object routeValues) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + htmlHelper.ViewContext, + null, // routeName + routeValues, + "post", // method + null)) // htmlAttributes + .Returns(tagBuilder) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginRouteForm(routeValues, suppressAntiforgery: true); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + [Theory] [MemberData(nameof(RouteNameDataSet))] public void BeginRouteFormWithRouteNameParameter_CallsHtmlGeneratorWithExpectedValues(string routeName) @@ -637,7 +987,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateRouteForm( + .Setup(g => g.GenerateRouteForm( htmlHelper.ViewContext, routeName, null, // routeValues @@ -645,6 +995,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -661,6 +1015,78 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlGenerator.Verify(); } + [Theory] + [MemberData(nameof(RouteNameDataSet))] + public void BeginRouteFormWithRouteNameParameter_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues( + string routeName) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + htmlHelper.ViewContext, + routeName, + null, // routeValues + "post", // method + null)) // htmlAttributes + .Returns(tagBuilder) + .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginRouteForm(routeName, suppressAntiforgery: false); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + + [Theory] + [MemberData(nameof(RouteNameDataSet))] + public void BeginRouteFormWithRouteNameParameter_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues( + string routeName) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + htmlHelper.ViewContext, + routeName, + null, // routeValues + "post", // method + null)) // htmlAttributes + .Returns(tagBuilder) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginRouteForm(routeName, suppressAntiforgery: true); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + [Theory] [MemberData(nameof(RouteNameAndRouteValuesDataSet))] public void BeginRouteFormWithRouteNameAndRouteValuesParameters_CallsHtmlGeneratorWithExpectedValues( @@ -672,7 +1098,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateRouteForm( + .Setup(g => g.GenerateRouteForm( htmlHelper.ViewContext, routeName, routeValues, @@ -680,6 +1106,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -707,7 +1137,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateRouteForm( + .Setup(g => g.GenerateRouteForm( htmlHelper.ViewContext, routeName, null, // routeValues @@ -715,6 +1145,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -743,7 +1177,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateRouteForm( + .Setup(g => g.GenerateRouteForm( htmlHelper.ViewContext, routeName, routeValues, @@ -751,6 +1185,10 @@ namespace Microsoft.AspNet.Mvc.Rendering null)) // htmlAttributes .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -779,7 +1217,7 @@ namespace Microsoft.AspNet.Mvc.Rendering var htmlGenerator = new Mock(MockBehavior.Strict); var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); htmlGenerator - .Setup(realHelper => realHelper.GenerateRouteForm( + .Setup(g => g.GenerateRouteForm( htmlHelper.ViewContext, routeName, null, // routeValues @@ -787,6 +1225,10 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlAttributes)) .Returns(tagBuilder) .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); // Guards Assert.NotNull(htmlHelper.ViewContext); @@ -802,5 +1244,91 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.Equal("", builder.ToString()); htmlGenerator.Verify(); } + + [Theory] + [MemberData(nameof(RouteNameMethodAndHtmlAttributesDataSet))] + public void BeginRouteFormWithRouteNameMethodAndHtmlAttributesParameters_WithAntiforgery_CallsHtmlGeneratorWithExpectedValues( + string routeName, + FormMethod method, + object htmlAttributes) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + htmlHelper.ViewContext, + routeName, + null, // routeValues + method.ToString().ToLowerInvariant(), + htmlAttributes)) + .Returns(tagBuilder) + .Verifiable(); + htmlGenerator + .Setup(g => g.GenerateAntiforgery(htmlHelper.ViewContext)) + .Returns(HtmlString.Empty) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginRouteForm( + routeName, + routeValues: null, + method: method, + suppressAntiforgery: false, + htmlAttributes: htmlAttributes); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } + + [Theory] + [MemberData(nameof(RouteNameMethodAndHtmlAttributesDataSet))] + public void BeginRouteFormWithRouteNameMethodAndHtmlAttributesParameters_SuppressAntiforgery_CallsHtmlGeneratorWithExpectedValues( + string routeName, + FormMethod method, + object htmlAttributes) + { + // Arrange + var tagBuilder = new TagBuilder(tagName: "form"); + var htmlGenerator = new Mock(MockBehavior.Strict); + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + htmlHelper.ViewContext, + routeName, + null, // routeValues + method.ToString().ToLowerInvariant(), + htmlAttributes)) + .Returns(tagBuilder) + .Verifiable(); + + // Guards + Assert.NotNull(htmlHelper.ViewContext); + var writer = Assert.IsAssignableFrom(htmlHelper.ViewContext.Writer); + var builder = writer.GetStringBuilder(); + Assert.NotNull(builder); + + // Act + var mvcForm = htmlHelper.BeginRouteForm( + routeName, + routeValues: null, + method: method, + suppressAntiforgery: true, + htmlAttributes: htmlAttributes); + + // Assert + Assert.NotNull(mvcForm); + Assert.Equal("", builder.ToString()); + htmlGenerator.Verify(); + } } } diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormTest.cs index de4577ee68..0c1134afea 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/HtmlHelperFormTest.cs @@ -151,6 +151,7 @@ namespace Microsoft.AspNet.Mvc.Rendering controllerName: null, routeValues: null, method: FormMethod.Post, + suppressAntiforgery: true, htmlAttributes: null); // Assert @@ -200,6 +201,7 @@ namespace Microsoft.AspNet.Mvc.Rendering controllerName: null, routeValues: null, method: FormMethod.Post, + suppressAntiforgery: true, htmlAttributes: htmlAttributes); // Assert @@ -247,7 +249,13 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.NotNull(builder); // Act - var mvcForm = htmlHelper.BeginForm(actionName, controllerName, routeValues, method, htmlAttributes); + var mvcForm = htmlHelper.BeginForm( + actionName, + controllerName, + routeValues, + method, + suppressAntiforgery: true, + htmlAttributes: htmlAttributes); // Assert Assert.NotNull(mvcForm); @@ -290,7 +298,12 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.NotNull(builder); // Act - var mvcForm = htmlHelper.BeginRouteForm(routeName, routeValues, method, htmlAttributes); + var mvcForm = htmlHelper.BeginRouteForm( + routeName, + routeValues, + method, + suppressAntiforgery: true, + htmlAttributes: htmlAttributes); // Assert Assert.NotNull(mvcForm); @@ -351,6 +364,255 @@ namespace Microsoft.AspNet.Mvc.Rendering builder.ToString()); } + // This is an integration for the implicit antiforgery token added by BeginForm. + [Fact] + public void BeginForm_EndForm_RendersAntiforgeryToken() + { + // Arrange + var htmlGenerator = new Mock(MockBehavior.Strict); + htmlGenerator + .Setup(g => g.GenerateForm( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(new TagBuilder("form")); + + htmlGenerator + .Setup(g => g.GenerateAntiforgery(It.IsAny())) + .Returns(new TagBuilder("antiforgery")); + + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + var serviceProvider = new Mock(); + serviceProvider.Setup(s => s.GetService(typeof(HtmlEncoder))).Returns(new HtmlTestEncoder()); + var viewContext = htmlHelper.ViewContext; + viewContext.HttpContext.RequestServices = serviceProvider.Object; + + var writer = viewContext.Writer as StringWriter; + Assert.NotNull(writer); + + // Act & Assert + using (var form = htmlHelper.BeginForm()) + { + Assert.True(viewContext.FormContext.HasAntiforgeryToken); + } + + Assert.Equal( + "", + writer.GetStringBuilder().ToString()); + } + + // This is an integration for the implicit antiforgery token added by BeginForm. + [Fact] + public void BeginForm_EndForm_RendersAntiforgeryToken_WithExplicitCallToAntiforgery() + { + // Arrange + var htmlGenerator = new Mock(MockBehavior.Strict); + htmlGenerator + .Setup(g => g.GenerateForm( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(new TagBuilder("form")); + + htmlGenerator + .Setup(g => g.GenerateAntiforgery(It.IsAny())) + .Returns(new TagBuilder("antiforgery")); + + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + var serviceProvider = new Mock(); + serviceProvider.Setup(s => s.GetService(typeof(HtmlEncoder))).Returns(new HtmlTestEncoder()); + var viewContext = htmlHelper.ViewContext; + viewContext.HttpContext.RequestServices = serviceProvider.Object; + + var writer = viewContext.Writer as StringWriter; + Assert.NotNull(writer); + + // Act & Assert + using (var form = htmlHelper.BeginForm()) + { + Assert.True(viewContext.FormContext.HasAntiforgeryToken); + + // This call will no-op + Assert.Same(HtmlString.Empty, htmlHelper.AntiForgeryToken()); + } + + Assert.Equal( + "
", + writer.GetStringBuilder().ToString()); + } + + // This is an integration for suppressing implicit antiforgery token added by BeginForm. + [Fact] + public void BeginForm_EndForm_SuppressAntiforgeryToken() + { + // Arrange + var htmlGenerator = new Mock(MockBehavior.Strict); + htmlGenerator + .Setup(g => g.GenerateForm( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(new TagBuilder("form")); + + htmlGenerator + .Setup(g => g.GenerateAntiforgery(It.IsAny())) + .Returns(new TagBuilder("antiforgery")); + + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + var serviceProvider = new Mock(); + serviceProvider.Setup(s => s.GetService(typeof(HtmlEncoder))).Returns(new HtmlTestEncoder()); + var viewContext = htmlHelper.ViewContext; + viewContext.HttpContext.RequestServices = serviceProvider.Object; + + var writer = viewContext.Writer as StringWriter; + Assert.NotNull(writer); + + // Act & Assert + using (var form = htmlHelper.BeginForm(FormMethod.Post, suppressAntiforgery: true, htmlAttributes: null)) + { + Assert.False(viewContext.FormContext.HasAntiforgeryToken); + } + + Assert.Equal( + "
", + writer.GetStringBuilder().ToString()); + } + + // This is an integration for suppressing implicit antiforgery token added by BeginForm. + [Fact] + public void BeginForm_EndForm_SuppressAntiforgeryToken_WithExplicitCallToAntiforgery() + { + // Arrange + var htmlGenerator = new Mock(MockBehavior.Strict); + htmlGenerator + .Setup(g => g.GenerateForm( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(new TagBuilder("form")); + + htmlGenerator + .Setup(g => g.GenerateAntiforgery(It.IsAny())) + .Returns(new TagBuilder("antiforgery")); + + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + var serviceProvider = new Mock(); + serviceProvider.Setup(s => s.GetService(typeof(HtmlEncoder))).Returns(new HtmlTestEncoder()); + var viewContext = htmlHelper.ViewContext; + viewContext.HttpContext.RequestServices = serviceProvider.Object; + + var writer = viewContext.Writer as StringWriter; + Assert.NotNull(writer); + + // Act & Assert + using (var form = htmlHelper.BeginForm(FormMethod.Post, suppressAntiforgery: true, htmlAttributes: null)) + { + Assert.False(viewContext.FormContext.HasAntiforgeryToken); + + // This call will ouput a token. + Assert.Equal("antiforgery", Assert.IsType(htmlHelper.AntiForgeryToken()).TagName); + } + + Assert.Equal( + "
", + writer.GetStringBuilder().ToString()); + } + + // This is an integration for the implicit antiforgery token added by BeginRouteForm. + [Fact] + public void BeginRouteForm_EndForm_RendersAntiforgeryToken() + { + // Arrange + var htmlGenerator = new Mock(MockBehavior.Strict); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(new TagBuilder("form")); + + htmlGenerator + .Setup(g => g.GenerateAntiforgery(It.IsAny())) + .Returns(new TagBuilder("antiforgery")); + + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + var serviceProvider = new Mock(); + serviceProvider.Setup(s => s.GetService(typeof(HtmlEncoder))).Returns(new HtmlTestEncoder()); + var viewContext = htmlHelper.ViewContext; + viewContext.HttpContext.RequestServices = serviceProvider.Object; + + var writer = viewContext.Writer as StringWriter; + Assert.NotNull(writer); + + // Act & Assert + using (var form = htmlHelper.BeginRouteForm(routeValues: null)) + { + Assert.True(viewContext.FormContext.HasAntiforgeryToken); + } + + Assert.Equal( + "
", + writer.GetStringBuilder().ToString()); + } + + // This is an integration for suppressing implicit antiforgery token added by BeginRouteForm. + [Fact] + public void BeginRouteForm_EndForm_SuppressAntiforgeryToken() + { + // Arrange + var htmlGenerator = new Mock(MockBehavior.Strict); + htmlGenerator + .Setup(g => g.GenerateRouteForm( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(new TagBuilder("form")); + + htmlGenerator + .Setup(g => g.GenerateAntiforgery(It.IsAny())) + .Returns(new TagBuilder("antiforgery")); + + var htmlHelper = DefaultTemplatesUtilities.GetHtmlHelper(htmlGenerator.Object); + var serviceProvider = new Mock(); + serviceProvider.Setup(s => s.GetService(typeof(HtmlEncoder))).Returns(new HtmlTestEncoder()); + var viewContext = htmlHelper.ViewContext; + viewContext.HttpContext.RequestServices = serviceProvider.Object; + + var writer = viewContext.Writer as StringWriter; + Assert.NotNull(writer); + + // Act & Assert + using (var form = htmlHelper.BeginRouteForm( + routeName: null, + routeValues: null, + method: FormMethod.Post, + suppressAntiforgery: true, + htmlAttributes: null)) + { + Assert.False(viewContext.FormContext.HasAntiforgeryToken); + } + + Assert.Equal( + "
", + writer.GetStringBuilder().ToString()); + } + private string GetHtmlAttributesAsString(object htmlAttributes) { var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultEditorTemplatesTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultEditorTemplatesTest.cs index d5d801fe6e..b47ac79700 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultEditorTemplatesTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultEditorTemplatesTest.cs @@ -1002,6 +1002,7 @@ Environment.NewLine; string controllerName, object routeValues, FormMethod method, + bool antiforgery, object htmlAttributes) { throw new NotImplementedException(); @@ -1011,6 +1012,7 @@ Environment.NewLine; string routeName, object routeValues, FormMethod method, + bool antiforgery, object htmlAttributes) { throw new NotImplementedException(); diff --git a/test/WebSites/BasicWebSite/Areas/Area1/Views/RemoteAttribute_Home/Create.cshtml b/test/WebSites/BasicWebSite/Areas/Area1/Views/RemoteAttribute_Home/Create.cshtml index a80f26c9ef..0ffd8d7c8b 100644 --- a/test/WebSites/BasicWebSite/Areas/Area1/Views/RemoteAttribute_Home/Create.cshtml +++ b/test/WebSites/BasicWebSite/Areas/Area1/Views/RemoteAttribute_Home/Create.cshtml @@ -8,7 +8,7 @@ }

@ViewBag.Title

-@using (Html.BeginForm()) +@using (Html.BeginForm(FormMethod.Post, htmlAttributes: null, suppressAntiforgery: true)) {

Person

diff --git a/test/WebSites/BasicWebSite/Views/RemoteAttribute_Home/Create.cshtml b/test/WebSites/BasicWebSite/Views/RemoteAttribute_Home/Create.cshtml index a80f26c9ef..0ffd8d7c8b 100644 --- a/test/WebSites/BasicWebSite/Views/RemoteAttribute_Home/Create.cshtml +++ b/test/WebSites/BasicWebSite/Views/RemoteAttribute_Home/Create.cshtml @@ -8,7 +8,7 @@ }

@ViewBag.Title

-@using (Html.BeginForm()) +@using (Html.BeginForm(FormMethod.Post, htmlAttributes: null, suppressAntiforgery: true)) {

Person

diff --git a/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithoutLayout.cshtml b/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithoutLayout.cshtml index 90f033739e..05cfe01c41 100644 --- a/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithoutLayout.cshtml +++ b/test/WebSites/RazorWebSite/Views/FlushPoint/PageWithoutLayout.cshtml @@ -5,7 +5,7 @@ Secondary content @{ await Html.RenderPartialAsync("_PartialWithFlush"); } -@using (Html.BeginForm()) +@using (Html.BeginForm(method: FormMethod.Post, suppressAntiforgery: true, htmlAttributes: null)) { @Html.TextBox("Name1") @await FlushAsync()