From b30020a6550040fced72690f96e1cfbb7d39b80d Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 24 Jan 2018 17:54:21 -0800 Subject: [PATCH] PartialTagHelper should not fallback to the current page's model if asp-for expression exists Fixes #7295 --- .../PartialTagHelper.cs | 4 +- .../HtmlGenerationTest.cs | 1 + ...oductListUsingTagHelpersWithNullModel.html | 30 ++++++++++++ .../PartialTagHelperTest.cs | 46 +++++++++++++++++++ .../HtmlGeneration_HomeController.cs | 10 ++++ 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductListUsingTagHelpersWithNullModel.html diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/PartialTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/PartialTagHelper.cs index 8d26b511ff..59b7d5d30e 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/PartialTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/PartialTagHelper.cs @@ -101,7 +101,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var view = viewEngineResult.View; // Determine which ViewData we should use to construct a new ViewData var baseViewData = ViewData ?? ViewContext.ViewData; - var model = For?.Model ?? ViewContext.ViewData.Model; + + // Use the rendering View's model only if an asp-for expression does not exist + var model = For != null ? For.Model : ViewContext.ViewData.Model; var newViewData = new ViewDataDictionary(baseViewData, model); var partialViewContext = new ViewContext(ViewContext, view, newViewData, writer); diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs index db7411fff9..07d5712894 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/HtmlGenerationTest.cs @@ -67,6 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests // Testing InputTagHelpers invoked in the partial views { "ProductList", "/HtmlGeneration_Product" }, { "ProductListUsingTagHelpers", "/HtmlGeneration_Product" }, + { "ProductListUsingTagHelpersWithNullModel", "/HtmlGeneration_Product" }, // Testing the ScriptTagHelper { "Script", null }, }; diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductListUsingTagHelpersWithNullModel.html b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductListUsingTagHelpersWithNullModel.html new file mode 100644 index 0000000000..2fcbfd25fa --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/HtmlGenerationWebSite.HtmlGeneration_Home.ProductListUsingTagHelpersWithNullModel.html @@ -0,0 +1,30 @@ + + + + + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
HtmlFieldPrefix =
+ +
+ + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/PartialTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/PartialTagHelperTest.cs index 937e95ad44..c7a08e299f 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/PartialTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/PartialTagHelperTest.cs @@ -233,6 +233,52 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers view.Verify(); } + [Fact] + public async Task ProcessAsync_DoesNotUseModelFromViewdata_IfModelExpressionEvalulatesToNull() + { + // Arrange + var bufferScope = new TestViewBufferScope(); + var partialName = "_Partial"; + var modelMetadataProvider = new TestModelMetadataProvider(); + var containerModel = new TestModel { Property = null }; + var containerModelExplorer = modelMetadataProvider.GetModelExplorerForType( + typeof(TestModel), + containerModel); + var propertyModelExplorer = containerModelExplorer.GetExplorerForProperty(nameof(TestModel.Property)); + + var modelExpression = new ModelExpression("Property", propertyModelExplorer); + var viewContext = GetViewContext(); + viewContext.ViewData.Model = new object(); + + var view = new Mock(); + view.Setup(v => v.RenderAsync(It.IsAny())) + .Callback((ViewContext v) => + { + Assert.Null(v.ViewData.Model); + }) + .Returns(Task.CompletedTask) + .Verifiable(); + + var viewEngine = new Mock(); + viewEngine.Setup(v => v.GetView(It.IsAny(), partialName, false)) + .Returns(ViewEngineResult.Found(partialName, view.Object)); + + var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope) + { + Name = partialName, + ViewContext = viewContext, + For = modelExpression, + }; + var tagHelperContext = GetTagHelperContext(); + var output = GetTagHelperOutput(); + + // Act + await tagHelper.ProcessAsync(tagHelperContext, output); + + // Assert + view.Verify(); + } + [Fact] public async Task ProcessAsync_SetsHtmlFieldPrefix_UsingModelExpression() { diff --git a/test/WebSites/HtmlGenerationWebSite/Controllers/HtmlGeneration_HomeController.cs b/test/WebSites/HtmlGenerationWebSite/Controllers/HtmlGeneration_HomeController.cs index c0f4560c1e..d41eb9100e 100644 --- a/test/WebSites/HtmlGenerationWebSite/Controllers/HtmlGeneration_HomeController.cs +++ b/test/WebSites/HtmlGenerationWebSite/Controllers/HtmlGeneration_HomeController.cs @@ -110,6 +110,16 @@ namespace HtmlGenerationWebSite.Controllers public IActionResult ProductListUsingTagHelpers() => View(_products); + public IActionResult ProductListUsingTagHelpersWithNullModel() + { + var model = new List + { + null, + }; + + return View(nameof(ProductListUsingTagHelpers), model); + } + public IActionResult EmployeeList() { var employees = new List