IHtmlContent WriteTo is invoked after dispose of parent component scope
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
I am trying to develop a fluent framework for bootstrap (https://github.com/burcinsahin/FluentBootstrapCore) and I have an example usage as below.
```
@using (Html.Bootstrap().Form().Begin())
{
@Html.Bootstrap().Input()
}
```
Here container form dispose is invoked before Input WriteTo method. Input is some class extends.NetCore Built-in IHtmlContent interface.
Begin writes to HtmlHelper ViewContext to manually and after dispose it ends the tag in the same way. Here the html output written to page is correct and I do not have any problem there.
```
public class ComponentBuilder : IDisposable
where TComponent : SingleComponent
{
protected readonly IHtmlHelper _htmlHelper;
protected readonly TComponent _component;
internal IHtmlHelper HtmlHelper => _htmlHelper;
internal TComponent Component => _component;
public ComponentBuilder(IHtmlHelper htmlHelper, TComponent component)
{
_htmlHelper = htmlHelper;
_component = component;
_htmlHelper.ViewContext.Writer.Write(_component.Begin());
_htmlHelper.ViewContext.Writer.Write(_component.Body());
}
public void Dispose()
{
Debug.WriteLine($"ComponentBuilder.Dispose for {typeof(TComponent).Name} invoked.");
_htmlHelper.ViewContext.Writer.Write(_component.End());
}
}
```
```
public class BootstrapContent : IHtmlContent
where TComponent : SingleComponent
{
private readonly TComponent _component;
private readonly IHtmlHelper _htmlHelper;
internal TComponent Component => _component;
internal IHtmlHelper HtmlHelper => _htmlHelper;
public BootstrapContent(IHtmlHelper htmlHelper, TComponent component)
{
_htmlHelper = htmlHelper;
_component = component;
}
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
{
Debug.WriteLine($"BootstrapContent.WriteTo for {typeof(TComponent).Name} invoked.");
var html = _component.ToHtml();
writer.Write(html);
}
public ComponentBuilder Begin()
{
Debug.WriteLine($"BootstrapContent.Begin for {typeof(TComponent).Name} invoked.");
return new ComponentBuilder(_htmlHelper, _component);
}
}
```
Problem is: I have a stack for components and because of this interesting order of invokes, I can not push or pop the stack in the correct order. Parent is disposed and empties the stack then the component inside starts its operations and finds an empty stack when needed.
Output is as below:
```
BootstrapContent.Begin for Form invoked.
ComponentBuilder.Dispose for Form invoked.
BootstrapContent.WriteTo for Input invoked.
```
Here is the call stack (ExternalCode) where WriteTo method invoked:
[![screencaptured][1]][1]
Note: I use .Net (Core) 6 for application layer and .NetStandart 2.1 for class libraries, when I changed all them to .Net (Core) 7 it still behaves in the same way. I have created a branch named "issue/dispose" for anyone who wants to review this issue.
So, this problem seems as a big issue and blocks me. Anyone who knows why the dispose method is invoked before the component inside the "using" scope.
Thanks in advance.
[1]: https://i.stack.imgur.com/nT3vP.png
Contributor guide
Research direction
Start by reproducing the reported order using ComponentBuilder.Dispose, BootstrapContent.Begin, and BootstrapContent.WriteTo, then inspect the ViewContext.Writer calls and the provided call stack. Compare the observed lifecycle with the issue's using-scope example and determine whether the behavior is an ASP.NET Core defect or an expected rendering order; a useful outcome should document the cause or identify a narrowly scoped fix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100