parent
41104bff7e
commit
e6c716444d
|
|
@ -15,9 +15,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
/// <paramref name="context"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ActionContext"/>.</param>
|
||||
/// <param name="pageName">The name of the page.</param>
|
||||
/// <param name="pageName">The name or path of the page.</param>
|
||||
/// <returns>The <see cref="RazorPageResult"/> of locating the page.</returns>
|
||||
/// <remarks><seealso cref="IViewEngine.FindView"/>.</remarks>
|
||||
/// <remarks>
|
||||
/// <remarks>Use <see cref="GetPage(string, string)"/> when the absolute or relative
|
||||
/// path of the page is known.</remarks>
|
||||
/// <seealso cref="IViewEngine.FindView"/>.
|
||||
/// </remarks>
|
||||
RazorPageResult FindPage(ActionContext context, string pageName);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders a partial view.
|
||||
/// </summary>
|
||||
[HtmlTargetElement("partial", Attributes = "name", TagStructure = TagStructure.WithoutEndTag)]
|
||||
public class PartialTagHelper : TagHelper
|
||||
{
|
||||
private const string ForAttributeName = "asp-for";
|
||||
private readonly ICompositeViewEngine _viewEngine;
|
||||
private readonly IViewBufferScope _viewBufferScope;
|
||||
|
||||
public PartialTagHelper(
|
||||
ICompositeViewEngine viewEngine,
|
||||
IViewBufferScope viewBufferScope)
|
||||
{
|
||||
_viewEngine = viewEngine ?? throw new ArgumentNullException(nameof(viewEngine));
|
||||
_viewBufferScope = viewBufferScope ?? throw new ArgumentNullException(nameof(viewBufferScope));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name or path of the partial view that is rendered to the response.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An expression to be evaluated against the current model.
|
||||
/// </summary>
|
||||
[HtmlAttributeName(ForAttributeName)]
|
||||
public ModelExpression For { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ViewDataDictionary"/> to pass into the partial view.
|
||||
/// </summary>
|
||||
public ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
[HtmlAttributeNotBound]
|
||||
[ViewContext]
|
||||
public ViewContext ViewContext { get; set; }
|
||||
|
||||
/// <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(context));
|
||||
}
|
||||
|
||||
var viewBuffer = new ViewBuffer(_viewBufferScope, Name, ViewBuffer.PartialViewPageSize);
|
||||
using (var writer = new ViewBufferTextWriter(viewBuffer, Encoding.UTF8))
|
||||
{
|
||||
await RenderPartialViewAsync(writer);
|
||||
|
||||
// Reset the TagName. We don't want `partial` to render.
|
||||
output.TagName = null;
|
||||
output.Content.SetHtmlContent(viewBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RenderPartialViewAsync(TextWriter writer)
|
||||
{
|
||||
var viewEngineResult = _viewEngine.GetView(ViewContext.ExecutingFilePath, Name, isMainPage: false);
|
||||
var getViewLocations = viewEngineResult.SearchedLocations;
|
||||
if (!viewEngineResult.Success)
|
||||
{
|
||||
viewEngineResult = _viewEngine.FindView(ViewContext, Name, isMainPage: false);
|
||||
}
|
||||
|
||||
if (!viewEngineResult.Success)
|
||||
{
|
||||
var searchedLocations = Enumerable.Concat(getViewLocations, viewEngineResult.SearchedLocations);
|
||||
var locations = string.Empty;
|
||||
if (searchedLocations.Any())
|
||||
{
|
||||
locations += Environment.NewLine + string.Join(Environment.NewLine, searchedLocations);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatViewEngine_PartialViewNotFound(Name, locations));
|
||||
}
|
||||
|
||||
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;
|
||||
var newViewData = new ViewDataDictionary<object>(baseViewData, model);
|
||||
var partialViewContext = new ViewContext(ViewContext, view, newViewData, writer);
|
||||
|
||||
if (For?.Name != null)
|
||||
{
|
||||
newViewData.TemplateInfo.HtmlFieldPrefix = newViewData.TemplateInfo.GetFullHtmlFieldName(For.Name);
|
||||
}
|
||||
|
||||
using (view as IDisposable)
|
||||
{
|
||||
await view.RenderAsync(partialViewContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,6 +178,20 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
internal static string FormatArgumentCannotContainHtmlSpace()
|
||||
=> GetString("ArgumentCannotContainHtmlSpace");
|
||||
|
||||
/// <summary>
|
||||
/// The partial view '{0}' was not found. The following locations were searched:{1}
|
||||
/// </summary>
|
||||
internal static string ViewEngine_PartialViewNotFound
|
||||
{
|
||||
get => GetString("ViewEngine_PartialViewNotFound");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The partial view '{0}' was not found. The following locations were searched:{1}
|
||||
/// </summary>
|
||||
internal static string FormatViewEngine_PartialViewNotFound(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("ViewEngine_PartialViewNotFound"), p0, p1);
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -153,4 +153,7 @@
|
|||
<data name="ArgumentCannotContainHtmlSpace" xml:space="preserve">
|
||||
<value>Value cannot contain HTML space characters.</value>
|
||||
</data>
|
||||
<data name="ViewEngine_PartialViewNotFound" xml:space="preserve">
|
||||
<value>The partial view '{0}' was not found. The following locations were searched:{1}</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// <summary>
|
||||
/// Creates a <see cref="ViewResult"/> object by specifying a <paramref name="viewName"/>.
|
||||
/// </summary>
|
||||
/// <param name="viewName">The name of the view that is rendered to the response.</param>
|
||||
/// <param name="viewName">The name or path of the view that is rendered to the response.</param>
|
||||
/// <returns>The created <see cref="ViewResult"/> object for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual ViewResult View(string viewName)
|
||||
|
|
@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// Creates a <see cref="ViewResult"/> object by specifying a <paramref name="viewName"/>
|
||||
/// and the <paramref name="model"/> to be rendered by the view.
|
||||
/// </summary>
|
||||
/// <param name="viewName">The name of the view that is rendered to the response.</param>
|
||||
/// <param name="viewName">The name or path of the view that is rendered to the response.</param>
|
||||
/// <param name="model">The model that is rendered by the view.</param>
|
||||
/// <returns>The created <see cref="ViewResult"/> object for the response.</returns>
|
||||
[NonAction]
|
||||
|
|
@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// <summary>
|
||||
/// Creates a <see cref="PartialViewResult"/> object by specifying a <paramref name="viewName"/>.
|
||||
/// </summary>
|
||||
/// <param name="viewName">The name of the view that is rendered to the response.</param>
|
||||
/// <param name="viewName">The name or path of the partial view that is rendered to the response.</param>
|
||||
/// <returns>The created <see cref="PartialViewResult"/> object for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual PartialViewResult PartialView(string viewName)
|
||||
|
|
@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// Creates a <see cref="PartialViewResult"/> object by specifying a <paramref name="viewName"/>
|
||||
/// and the <paramref name="model"/> to be rendered by the partial view.
|
||||
/// </summary>
|
||||
/// <param name="viewName">The name of the partial view that is rendered to the response.</param>
|
||||
/// <param name="viewName">The name or path of the partial view that is rendered to the response.</param>
|
||||
/// <param name="model">The model that is rendered by the partial view.</param>
|
||||
/// <returns>The created <see cref="PartialViewResult"/> object for the response.</returns>
|
||||
[NonAction]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.Controllers;
|
|||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc
|
||||
|
|
@ -23,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public int? StatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the partial view to render.
|
||||
/// Gets or sets the name or path of the partial view that is rendered to the response.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When <c>null</c>, defaults to <see cref="ControllerActionDescriptor.ActionName"/>.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path 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="IHtmlContent"/> instance containing
|
||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
|
|
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Returns a new <see cref="IHtmlContent"/> instance containing the created HTML.
|
||||
|
|
@ -137,7 +137,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
|
|
@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <returns>
|
||||
|
|
@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <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>
|
||||
|
|
@ -239,7 +239,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In this context, "renders" means the method writes its output using <see cref="ViewContext.Writer"/>.
|
||||
|
|
@ -267,7 +267,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <remarks>
|
||||
|
|
@ -297,7 +297,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <remarks>
|
||||
|
|
@ -327,7 +327,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <returns>A <see cref="Task"/> that renders the created HTML when it executes.</returns>
|
||||
/// <remarks>
|
||||
|
|
@ -355,7 +355,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
|
||||
/// <returns>A <see cref="Task"/> that renders the created HTML when it executes.</returns>
|
||||
|
|
@ -385,7 +385,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// </summary>
|
||||
/// <param name="htmlHelper">The <see cref="IHtmlHelper"/> instance this method extends.</param>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <param name="model">A model to pass into the partial view.</param>
|
||||
/// <returns>A <see cref="Task"/> that renders the created HTML when it executes.</returns>
|
||||
|
|
|
|||
|
|
@ -570,7 +570,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
|
|||
/// Renders HTML markup for the specified partial view.
|
||||
/// </summary>
|
||||
/// <param name="partialViewName">
|
||||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// The name or path of the partial view used to create the HTML markup. Must not be <c>null</c>.
|
||||
/// </param>
|
||||
/// <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>
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ namespace Microsoft.AspNetCore.Mvc.ViewEngines
|
|||
/// <paramref name="context"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ActionContext"/>.</param>
|
||||
/// <param name="viewName">The name of the view.</param>
|
||||
/// <param name="viewName">The name or path of the view that is rendered to the response.</param>
|
||||
/// <param name="isMainPage">Determines if the page being found is the main page for an action.</param>
|
||||
/// <returns>The <see cref="ViewEngineResult"/> of locating the view.</returns>
|
||||
/// <remarks>Use <see cref="GetView(string, string, bool)"/> when the absolute or relative
|
||||
/// path of the view is known.</remarks>
|
||||
ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.Controllers;
|
|||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc
|
||||
|
|
@ -23,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public int? StatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the view to render.
|
||||
/// Gets or sets the name or path of the view that is rendered to the response.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When <c>null</c>, defaults to <see cref="ControllerActionDescriptor.ActionName"/>.
|
||||
|
|
|
|||
|
|
@ -61,8 +61,12 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
// Only attribute order should differ.
|
||||
{ "Order", "/HtmlGeneration_Order/Submit" },
|
||||
{ "OrderUsingHtmlHelpers", "/HtmlGeneration_Order/Submit" },
|
||||
// Testing PartialTagHelper
|
||||
{ "PartialTagHelperWithoutModel", null },
|
||||
{ "Warehouse", null },
|
||||
// Testing InputTagHelpers invoked in the partial views
|
||||
{ "ProductList", "/HtmlGeneration_Product" },
|
||||
{ "ProductListUsingTagHelpers", "/HtmlGeneration_Product" },
|
||||
// Testing the ScriptTagHelper
|
||||
{ "Script", null },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
PartialTagHelperWithoutModel: Hello from partial
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<form action="/HtmlGeneration_Product" method="post">
|
||||
<div>
|
||||
<label class="product" for="z0__HomePage">HomePage</label>
|
||||
<input type="url" size="50" disabled="disabled" readonly="readonly" id="z0__HomePage" name="[0].HomePage" value="http://www.contoso.com/" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="product" for="z0__Number">Number</label>
|
||||
<input type="number" data-val="true" data-val-required="The Number field is required." id="z0__Number" name="[0].Number" value="0" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z0__ProductName">ProductName</label>
|
||||
<input type="text" data-val="true" data-val-required="The ProductName field is required." id="z0__ProductName" name="[0].ProductName" value="Product_0" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z0__Description">Description</label>
|
||||
<textarea rows="4" cols="50" class="product" id="z0__Description" name="[0].Description">
|
||||
</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z1__HomePage">HomePage</label>
|
||||
<input type="url" size="50" disabled="disabled" readonly="readonly" id="z1__HomePage" name="[1].HomePage" value="" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="product" for="z1__Number">Number</label>
|
||||
<input type="number" data-val="true" data-val-required="The Number field is required." id="z1__Number" name="[1].Number" value="1" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z1__ProductName">ProductName</label>
|
||||
<input type="text" data-val="true" data-val-required="The ProductName field is required." id="z1__ProductName" name="[1].ProductName" value="Product_1" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z1__Description">Description</label>
|
||||
<textarea rows="4" cols="50" class="product" id="z1__Description" name="[1].Description">
|
||||
</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z2__HomePage">HomePage</label>
|
||||
<input type="url" size="50" disabled="disabled" readonly="readonly" id="z2__HomePage" name="[2].HomePage" value="" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="product" for="z2__Number">Number</label>
|
||||
<input type="number" data-val="true" data-val-required="The Number field is required." id="z2__Number" name="[2].Number" value="2" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z2__ProductName">ProductName</label>
|
||||
<input type="text" data-val="true" data-val-required="The ProductName field is required." id="z2__ProductName" name="[2].ProductName" value="Product_2" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="product" for="z2__Description">Description</label>
|
||||
<textarea rows="4" cols="50" class="product" id="z2__Description" name="[2].Description">
|
||||
Product_2 description</textarea>
|
||||
</div>
|
||||
|
||||
<div>HtmlFieldPrefix = </div>
|
||||
<input type="submit" />
|
||||
<input name="__RequestVerificationToken" type="hidden" value="{0}" /></form>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<h3>City_1</h3>
|
||||
|
||||
<div>
|
||||
<label for="Employee_Name">Name</label>
|
||||
<input type="text" id="Employee_Name" name="Employee.Name" value="EmployeeName_1" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Employee_OfficeNumber">OfficeNumber</label>
|
||||
<input type="number" id="Employee_OfficeNumber" name="Employee.OfficeNumber" value="Number_1" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Employee_Address">Address</label>
|
||||
<textarea rows="4" cols="50" id="Employee_Address" name="Employee.Address">
|
||||
Address_1</textarea>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,473 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.TestCommon;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
{
|
||||
public class PartialTagHelperTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ProcessAsync_RendersPartialView_IfGetViewReturnsView()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "Hello world!";
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var model = new object();
|
||||
var viewContext = GetViewContext();
|
||||
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
v.Writer.Write(expected);
|
||||
})
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.Found(partialName, view.Object));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
var content = HtmlContentUtilities.HtmlContentToString(output.Content, new HtmlTestEncoder());
|
||||
Assert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_RendersPartialView_IfFindViewReturnsView()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "Hello world!";
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var model = new object();
|
||||
var viewContext = GetViewContext();
|
||||
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
v.Writer.Write(expected);
|
||||
})
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.NotFound(partialName, new[] { partialName }));
|
||||
|
||||
viewEngine.Setup(v => v.FindView(viewContext, partialName, false))
|
||||
.Returns(ViewEngineResult.Found(partialName, view.Object));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
var content = HtmlContentUtilities.HtmlContentToString(output.Content, new HtmlTestEncoder());
|
||||
Assert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_UsesViewDataFromContext()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "Implicit";
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var viewContext = GetViewContext();
|
||||
viewContext.ViewData["key"] = expected;
|
||||
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
v.Writer.Write(v.ViewData["key"]);
|
||||
})
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.NotFound(partialName, new[] { partialName }));
|
||||
|
||||
viewEngine.Setup(v => v.FindView(viewContext, partialName, false))
|
||||
.Returns(ViewEngineResult.Found(partialName, view.Object));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
var content = HtmlContentUtilities.HtmlContentToString(output.Content, new HtmlTestEncoder());
|
||||
Assert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_UsesPassedInViewData_WhenNotNull()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "Explicit";
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var model = new object();
|
||||
var viewData = new ViewDataDictionary(new TestModelMetadataProvider(), new ModelStateDictionary());
|
||||
viewData["key"] = expected;
|
||||
var viewContext = GetViewContext();
|
||||
viewContext.ViewData["key"] = "ViewContext";
|
||||
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
v.Writer.Write(v.ViewData["key"]);
|
||||
})
|
||||
.Returns(Task.CompletedTask);
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.Found(partialName, view.Object));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
ViewData = viewData,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
var content = HtmlContentUtilities.HtmlContentToString(output.Content, new HtmlTestEncoder());
|
||||
Assert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_UsesModelExpression_ToDetermineModel()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new PropertyModel();
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var modelMetadataProvider = new TestModelMetadataProvider();
|
||||
var containerModel = new TestModel { Property = expected };
|
||||
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<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
var actual = Assert.IsType<PropertyModel>(v.ViewData.Model);
|
||||
Assert.Same(expected, actual);
|
||||
})
|
||||
.Returns(Task.CompletedTask)
|
||||
.Verifiable();
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), 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()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "order.items[0].Property";
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var modelMetadataProvider = new TestModelMetadataProvider();
|
||||
var containerModel = new TestModel { Property = new PropertyModel() };
|
||||
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.TemplateInfo.HtmlFieldPrefix = "order.items[0]";
|
||||
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
Assert.Equal(expected, v.ViewData.TemplateInfo.HtmlFieldPrefix);
|
||||
})
|
||||
.Returns(Task.CompletedTask)
|
||||
.Verifiable();
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), 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();
|
||||
Assert.Equal("order.items[0]", viewContext.ViewData.TemplateInfo.HtmlFieldPrefix);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_UsesModelOnViewContextViewData_WhenModelExpresionIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var model = new object();
|
||||
var viewContext = GetViewContext();
|
||||
viewContext.ViewData.Model = model;
|
||||
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
Assert.Same(model, v.ViewData.Model);
|
||||
})
|
||||
.Returns(Task.CompletedTask)
|
||||
.Verifiable();
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.Found(partialName, view.Object));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
view.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_DoesNotModifyHtmlFieldPrefix_WhenModelExpressionIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "original";
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var model = new object();
|
||||
var viewContext = GetViewContext();
|
||||
viewContext.ViewData.Model = model;
|
||||
viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = expected;
|
||||
|
||||
var view = new Mock<IView>();
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Callback((ViewContext v) =>
|
||||
{
|
||||
Assert.Equal(expected, v.ViewData.TemplateInfo.HtmlFieldPrefix);
|
||||
})
|
||||
.Returns(Task.CompletedTask)
|
||||
.Verifiable();
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.Found(partialName, view.Object));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
view.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_DisposesViewInstance()
|
||||
{
|
||||
// Arrange
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var viewContext = GetViewContext();
|
||||
|
||||
var disposable = new Mock<IDisposable>();
|
||||
disposable.Setup(d => d.Dispose()).Verifiable();
|
||||
var view = disposable.As<IView>();
|
||||
|
||||
view.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
|
||||
.Returns(Task.CompletedTask)
|
||||
.Verifiable();
|
||||
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.Found(partialName, view.Object));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act
|
||||
await tagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
disposable.Verify();
|
||||
view.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_Throws_IfGetViewAndFindReturnNotFoundResults()
|
||||
{
|
||||
// Arrange
|
||||
var bufferScope = new TestViewBufferScope();
|
||||
var partialName = "_Partial";
|
||||
var expected = string.Join(Environment.NewLine,
|
||||
$"The partial view '{partialName}' was not found. The following locations were searched:",
|
||||
"NotFound1",
|
||||
"NotFound2",
|
||||
"NotFound3",
|
||||
"NotFound4");
|
||||
var viewData = new ViewDataDictionary(new TestModelMetadataProvider(), new ModelStateDictionary());
|
||||
var viewContext = GetViewContext();
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
var viewEngine = new Mock<ICompositeViewEngine>();
|
||||
viewEngine.Setup(v => v.GetView(It.IsAny<string>(), partialName, false))
|
||||
.Returns(ViewEngineResult.NotFound(partialName, new[] { "NotFound1", "NotFound2" }));
|
||||
|
||||
viewEngine.Setup(v => v.FindView(viewContext, partialName, false))
|
||||
.Returns(ViewEngineResult.NotFound(partialName, new[] { $"NotFound3", $"NotFound4" }));
|
||||
|
||||
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope)
|
||||
{
|
||||
Name = partialName,
|
||||
ViewContext = viewContext,
|
||||
ViewData = viewData,
|
||||
};
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var output = GetTagHelperOutput();
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => tagHelper.ProcessAsync(tagHelperContext, output));
|
||||
Assert.Equal(expected, exception.Message);
|
||||
}
|
||||
|
||||
private static ViewContext GetViewContext()
|
||||
{
|
||||
return new ViewContext(
|
||||
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
|
||||
NullView.Instance,
|
||||
new ViewDataDictionary(new TestModelMetadataProvider(), new ModelStateDictionary()),
|
||||
Mock.Of<ITempDataDictionary>(),
|
||||
TextWriter.Null,
|
||||
new HtmlHelperOptions());
|
||||
}
|
||||
|
||||
private static TagHelperContext GetTagHelperContext()
|
||||
{
|
||||
return new TagHelperContext(
|
||||
"partial",
|
||||
new TagHelperAttributeList(),
|
||||
new Dictionary<object, object>(),
|
||||
Guid.NewGuid().ToString("N"));
|
||||
}
|
||||
|
||||
private static TagHelperOutput GetTagHelperOutput()
|
||||
{
|
||||
return new TagHelperOutput(
|
||||
"partial",
|
||||
new TagHelperAttributeList(),
|
||||
(_, __) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent()));
|
||||
}
|
||||
|
||||
private class TestModel
|
||||
{
|
||||
public PropertyModel Property { get; set; }
|
||||
}
|
||||
|
||||
private class PropertyModel
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,6 +108,8 @@ namespace HtmlGenerationWebSite.Controllers
|
|||
return View(_products);
|
||||
}
|
||||
|
||||
public IActionResult ProductListUsingTagHelpers() => View(_products);
|
||||
|
||||
public IActionResult EmployeeList()
|
||||
{
|
||||
var employees = new List<Employee>
|
||||
|
|
@ -165,6 +167,22 @@ namespace HtmlGenerationWebSite.Controllers
|
|||
return View(warehouse);
|
||||
}
|
||||
|
||||
public IActionResult Warehouse()
|
||||
{
|
||||
var warehouse = new Warehouse
|
||||
{
|
||||
City = "City_1",
|
||||
Employee = new Employee
|
||||
{
|
||||
Name = "EmployeeName_1",
|
||||
OfficeNumber = "Number_1",
|
||||
Address = "Address_1",
|
||||
}
|
||||
};
|
||||
|
||||
return View(warehouse);
|
||||
}
|
||||
|
||||
public IActionResult Environment()
|
||||
{
|
||||
return View();
|
||||
|
|
@ -209,5 +227,7 @@ namespace HtmlGenerationWebSite.Controllers
|
|||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult PartialTagHelperWithoutModel() => View();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
PartialTagHelperWithoutModel: <partial name="../Shared/_Partial" />
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
@using HtmlGenerationWebSite.Models
|
||||
@model IList<Product>
|
||||
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<form asp-action="Index" asp-controller="HtmlGeneration_Product" asp-antiforgery="true">
|
||||
@for (var i = 0; i < Model.Count; i++)
|
||||
{
|
||||
<div>
|
||||
<label asp-for="@Model[i].HomePage" class="product"></label>
|
||||
<input asp-for="@Model[i].HomePage" type="url" size="50" disabled="disabled" readonly="readonly" />
|
||||
</div>
|
||||
<partial name="_ProductPartial" asp-for="@Model[i]" />
|
||||
}
|
||||
@* Print the HtmlFieldPrefix outside of the partial tag helper to ensure it hasn't been modified *@
|
||||
<div>HtmlFieldPrefix = @ViewData.TemplateInfo.HtmlFieldPrefix</div>
|
||||
<input type="submit" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@model HtmlGenerationWebSite.Models.Warehouse
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
<h3>@Html.DisplayFor(m => m.City)</h3>
|
||||
<partial name="_EmployeePartial" asp-for="Employee" />
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
@model HtmlGenerationWebSite.Models.Employee
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
<div>
|
||||
<label asp-for="Name"></label>
|
||||
<input asp-for="Name" type="text"/>
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="OfficeNumber"></label>
|
||||
<input asp-for="OfficeNumber" type="number"/>
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="Address"></label>
|
||||
<textarea asp-for="Address" rows="4" cols="50"></textarea>
|
||||
</div>
|
||||
|
|
@ -0,0 +1 @@
|
|||
Hello from partial
|
||||
Loading…
Reference in New Issue