-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
private readonly IViewBufferScope _viewBufferScope; | ||
|
||
public PartialTagHelper( | ||
IHtmlGenerator htmlGenerator, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could just put it on one line.
[ViewContext] | ||
public ViewContext ViewContext { get; set; } | ||
|
||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inheritdoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null
-check both parameters.
var newViewData = new ViewDataDictionary<object>(baseViewData, model); | ||
var partialViewContext = new ViewContext(viewContext, view, newViewData, writer); | ||
|
||
await viewEngineResult.View.RenderAsync(partialViewContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
await view.RenderAsync(...)
/// <summary> | ||
/// Renders HTML markup for the specified partial view. | ||
/// </summary> | ||
/// <param name="partialViewName"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong order. Should be below ViewContext.
/// 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>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably remove Must not be null
here or add it to both ViewContext
and writer
because we null check those.
.Verifiable(); | ||
viewEngine | ||
.Setup(v => v.FindView(It.IsAny<ActionContext>(), It.IsAny<string>(), /*isMainPage*/ false)) | ||
.Returns(ViewEngineResult.NotFound("test-view", new[] { "location3", "location4" })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume we have a test somewhere else where GetView
fails but FindView
succeeds? If not, it might be worth adding one.
} | ||
|
||
/// <summary> | ||
/// The name of the partial view used to create the HTML markup. Must not be <c>null</c>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this property must not be null
, why doesn't the setter throw
an ArgumentNullException
?
[ViewContext] | ||
public ViewContext ViewContext { get; set; } | ||
|
||
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null
-check both parameters.
{ | ||
"TypeId": "public class Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator : Microsoft.AspNetCore.Mvc.ViewFeatures.IHtmlGenerator", | ||
"MemberId": "public .ctor(Microsoft.AspNetCore.Antiforgery.IAntiforgery antiforgery, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Mvc.MvcViewOptions> optionsAccessor, Microsoft.AspNetCore.Mvc.ModelBinding.IModelMetadataProvider metadataProvider, Microsoft.AspNetCore.Mvc.Routing.IUrlHelperFactory urlHelperFactory, System.Text.Encodings.Web.HtmlEncoder htmlEncoder, Microsoft.AspNetCore.Mvc.ViewFeatures.ValidationHtmlAttributeProvider validationAttributeProvider)", | ||
"Kind": "Removal" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why make this breaking change? Can add a new constructor and deprecate the old.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah no breaking changes please.
{ | ||
"TypeId": "public interface Microsoft.AspNetCore.Mvc.ViewFeatures.IHtmlGenerator", | ||
"MemberId": "System.Threading.Tasks.Task RenderPartialViewAsync(Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext, System.String partialViewName, System.Object model, Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary viewData, System.IO.TextWriter writer)", | ||
"Kind": "Addition" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding something to an interface seems like an impossible change to make before 3.0. What makes this 🆗?
{ | ||
throw new ArgumentNullException(nameof(antiforgery)); | ||
} | ||
|
||
if (optionsAccessor == null) | ||
{ | ||
throw new ArgumentNullException(nameof(optionsAccessor)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rewriting these null
checks seems unnecessary. But, being inconsistent about it is Just Wrong:tm:
Also, did we change our mind about throw
expressions? They were against our unofficial guidelines at one point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should also remove breaking changes.
ViewData, | ||
writer); | ||
|
||
output.SuppressOutput(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will nuke any other content added by other TagHelper
s. If someone wants to add anything to the partial TagHelper
i'd say let them. Instead of suppressing output just set the TagName
to null to work nicely with anyone else.
public ViewDataDictionary ViewData { get; set; } | ||
|
||
[ViewContext] | ||
public ViewContext ViewContext { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[HtmlAttributeNotBound]
3002f4f
to
092c3db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆙 📅
/// <summary> | ||
/// A model to pass into the partial view. | ||
/// </summary> | ||
public object Model { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed this before. Why isn't this
[HtmlAttributeName(ForAttributeName)]
public ModelExpression For { get; set; }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked with @DamianEdwards and he doesn't think this should be a ModelExpression. He was fine leaving this property as is.
// Determine which ViewData we should use to construct a new ViewData | ||
var baseViewData = ViewData ?? ViewContext.ViewData; | ||
|
||
var newViewData = new ViewDataDictionary<object>(baseViewData, Model); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overloads of the PartialAsync(...)
and RenderPartialAsync(...)
helpers default the model they use to htmlHelper.ViewData.Model
. This instead defaults to null
, which is unexpected. Should do something similar to the HTML helpers here.
Always use ViewContext.ViewData.Model
since setting the ViewData
property should not change the Model
property's default.
var tagHelper = new PartialTagHelper(viewEngine.Object, bufferScope) | ||
{ | ||
Name = partialName, | ||
Model = model, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add tests where Model
(now For
) isn't set or is explicitly set to null
but a view is found.
foreach (var product in Model) | ||
{ | ||
@* Update HtmlFieldPrefix so generated for, id and name attribute values are correct. *@ | ||
ViewData.TemplateInfo.HtmlFieldPrefix = fieldPrefix + string.Format("[{0}]", index++); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wouldn't be necessary when using asp-for="[index++]"
.
} | ||
} | ||
|
||
private async Task RenderPartialViewAsync(TextWriter writer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a suggestion: Could make this tag helper an HtmlHelper
subclass which implements ITagHelper
. Would have to make ViewContext
a new
property that calls Contextualize(...)
in its setter but that should be the primary wrinkle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot the punchline: Then could use RenderPartialCoreAsync(...)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sample @DamianEdwards has essentially DIs a IHtmlHelper
, Contextualizes
it and then renders the view using it. That kinda felt odd since we don't have any other use cases of doing this in any other tag helper. Given we already have a similarish copy of the code in PartialViewExecutor, I didn't think it was terrible to have yet another copy of it here.
092c3db
to
c6ea066
Compare
🆙 📅 |
c6ea066
to
e5110fe
Compare
} | ||
|
||
/// <summary> | ||
/// The name of the partial view used to create the HTML markup. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this do just view "names" (e.g. _LoginPartial
) or does it also do paths? Do we need to be clear about this in the docs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see any tests using a path, but would it work? And if paths aren't supported:
- Should they be?
- The docs need to be clearer about what a "partial view name" is (perhaps by giving an example)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like these properties are handled identically to e.g. viewName
parameters in Controller.View(...)
methods. Those are generally documented as The name of the view that is rendered to the response.
. Same for the corresponding result properties e.g. ViewResult.ViewName
.
If we need more documentation about what names, paths, et cetera mean, suggest we handle that in a separate issue. For now, let's be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does path - https://github.com/aspnet/Mvc/pull/7089/files#diff-883159b6acb104f0fb64afa28c27a9ccR2 . The name I think comes from the IHtmlHelper docs. I'd be happy to update it if you have suggestions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, and "partial view name" doesn't appear anywhere. Isn't "name of the partial view" clear enough (assuming we stick with just "name" for now)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, let's be consistent.
I'd rather have correct information than have consistent-but-useless information
Oh, and "partial view name" doesn't appear anywhere.
These mean the same thing so I don't think this is critical.
...
So, let's come up with some good wording here and then apply elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How 'bout "The name or path of the [partial] view that is rendered to the response." We do lots of shenanigans under the covers handling absolute and relative paths as well as distinguishing paths from names. But, describing exactly how we choose to interpret "name" versus "path" doesn't help much -- especially because it's specific to the RazorViewEngine
.
I'm not positive what extra words we need to inform readers what distinguishes a "partial" view. It's a view found with isMainPage: false
but the interfaces say only that isMainPage
"Determines if the page being found is the main page for an action.". The details are again specific to the IViewEngine
implementation. (For RazorViewEngine
, this parameter mainly controls whether or not _ViewStart.cshtml
files are used.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM but get final word from @Eilon on the doc comments.
if (For?.Name != null) | ||
{ | ||
newViewData.TemplateInfo.HtmlFieldPrefix = newViewData.TemplateInfo.GetFullHtmlFieldName(For.Name); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could move everything except var partialViewContext = ...;
outside the using
. Up to you.
Fixes #5916